Railway Operation Simulator  v2.9.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
241 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
242 {
243  if(lower.second < higher.second)
244  {
245  return(true);
246  }
247  else if(lower.second > higher.second)
248  {
249  return(false);
250  }
251  else if(lower.second == higher.second)
252  {
253  if(lower.first < higher.first)
254  {
255  return(true);
256  }
257  }
258  return(false);
259 }
260 
261 // ---------------------------------------------------------------------------
262 // PrefDirElement Functions
263 // ---------------------------------------------------------------------------
264 
265 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
266  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
267  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
268 {
269  if(!EntryExitNumber())
270  {
271  throw Exception("EXNumber failure in TPrefDirElement constructor");
272  }
275 }
276 
277 // ---------------------------------------------------------------------------
278 
279 AnsiString TPrefDirElement::LogPrefDir() const
280 // for debugging when passed as a call parameter
281 {
282  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
283  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
284  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
285  AnsiString(TrainIDOnBridgeTrackPos23);
286 
287 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
288  return(LogString);
289 }
290 
291 // ---------------------------------------------------------------------------
292 
293 bool TPrefDirElement::EntryExitNumber() // true for valid number
294 /*
295  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
296  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
297  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
298  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
299  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
300  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
301  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
302  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
303  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
304 */
305 
306 {
307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
308  int EXArray[16][2] =
309  {{4, 6}, {2, 8}, // horizontal & vertical
310  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
311  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
312  {1, 9}, {3, 7}}; // forward & reverse diagonals
313 
314  int EXNum = -1;
315  int Entry, Exit;
316 
317  if(ELink > -1)
318  {
319  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
320  }
321  else if(Link[2] == -1)
322  {
323  Entry = Link[0];
324  }
325  else
326  {
327  Utilities->CallLogPop(122);
328  return(false);
329  }
330  if(XLink > -1)
331  {
332  Exit = XLink;
333  }
334  else if(Link[2] == -1)
335  {
336  Exit = Link[1];
337  }
338  else
339  {
340  Utilities->CallLogPop(123);
341  return(false);
342  }
343  for(int x = 0; x < 16; x++)
344  {
345  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
346  {
347  EXNum = x;
348  }
349  }
350  if(EXNum == -1)
351  {
352  Utilities->CallLogPop(124);
353  return(false);
354  }
355  int BrNum = -1;
356 
357 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
358  the graphic for each of which is different because of the shape of the overbridge. The basic
359  entry/exit value is computed above, and this used to select only from elements with that entry/exit
360  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
361  int BrEXArray[24][2] = {
362  {4,6},{2,8},{1,9},{3,7},
363  {1,9},{3,7},{1,9},{3,7},
364  {2,8},{4,6},{2,8},{4,6}
365 */
366 
367  if(TrackType == Bridge)
368  {
369  if(EXNum == 1)
370  {
371  if(SpeedTag == 49)
372  {
373  BrNum = 1 + 16;
374  }
375  else if(SpeedTag == 54)
376  {
377  BrNum = 8 + 16;
378  }
379  else if(SpeedTag == 55)
380  {
381  BrNum = 10 + 16;
382  }
383  }
384  else if(EXNum == 0)
385  {
386  if(SpeedTag == 48)
387  {
388  BrNum = 0 + 16;
389  }
390  else if(SpeedTag == 58)
391  {
392  BrNum = 11 + 16;
393  }
394  else if(SpeedTag == 59)
395  {
396  BrNum = 9 + 16;
397  }
398  }
399  else if(EXNum == 14)
400  {
401  if(SpeedTag == 50)
402  {
403  BrNum = 2 + 16;
404  }
405  else if(SpeedTag == 52)
406  {
407  BrNum = 4 + 16;
408  }
409  else if(SpeedTag == 57)
410  {
411  BrNum = 6 + 16;
412  }
413  }
414  else if(EXNum == 15)
415  {
416  if(SpeedTag == 51)
417  {
418  BrNum = 3 + 16;
419  }
420  else if(SpeedTag == 53)
421  {
422  BrNum = 7 + 16;
423  }
424  else if(SpeedTag == 56)
425  {
426  BrNum = 5 + 16;
427  }
428  }
429  }
430  if(BrNum == -1)
431  {
432  EXNumber = EXNum;
433  }
434  else
435  {
436  EXNumber = BrNum;
437  }
438  Utilities->CallLogPop(125);
439  return(true);
440 }
441 
442 // ---------------------------------------------------------------------------
443 
445 /*
446  This is the basic track graphic for use in plotting the original graphic during route flashing.
447  Enter with all set apart from EXGraphic & EntryDirectionGraphic
448 */
449 {
450  if(SpeedTag == 64)
451  {
452  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
453 
454  }
455  if(SpeedTag == 65)
456  {
457  return(RailGraphics->LinkGraphicsPtr[17]);
458  }
459  if(SpeedTag == 66)
460  {
461  return(RailGraphics->LinkGraphicsPtr[18]);
462  }
463  if(SpeedTag == 67)
464  {
465  return(RailGraphics->LinkGraphicsPtr[19]);
466  }
467  if(SpeedTag == 80)
468  {
469  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
470 
471  }
472  if(SpeedTag == 81)
473  {
474  return(RailGraphics->LinkGraphicsPtr[21]);
475  }
476  if(SpeedTag == 82)
477  {
478  return(RailGraphics->LinkGraphicsPtr[22]);
479  }
480  if(SpeedTag == 83)
481  {
482  return(RailGraphics->LinkGraphicsPtr[23]);
483  }
484  if(SpeedTag == 84)
485  {
486  return(RailGraphics->LinkGraphicsPtr[24]);
487  }
488  if(SpeedTag == 85)
489  {
490  return(RailGraphics->LinkGraphicsPtr[25]);
491  }
492  if(SpeedTag == 86)
493  {
494  return(RailGraphics->LinkGraphicsPtr[26]);
495  }
496  if(SpeedTag == 87)
497  {
498  return(RailGraphics->LinkGraphicsPtr[27]);
499  }
500  if(SpeedTag == 129)
501  {
502  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
503 
504  }
505  if(SpeedTag == 130)
506  {
507  return(RailGraphics->LinkGraphicsPtr[29]);
508  }
509  if(XLinkPos == -1) // not set, could be first element or last element = leading point
510  {
511 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
512 // Points & don't want to display these)
513  if(Link[2] != -1)
514  {
515  return(0); // i.e. complex element, don't display
516  }
517  else
518  {
519  if(!EntryExitNumber())
520  {
521  throw Exception("Error in EntryExitNumber 4");
522  }
523  else
524  {
526  }
527  }
528  }
529  if(EXNumber > 15) // underbridge
530  {
531  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
532  }
533  else
534  {
536  }
537 }
538 
539 // ---------------------------------------------------------------------------
540 
542 /*
543  As above but for PrefDir graphics.
544 */
545 {
546  if(SpeedTag == 64)
547  {
548  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
549 
550  }
551  if(SpeedTag == 65)
552  {
554  }
555  if(SpeedTag == 66)
556  {
558  }
559  if(SpeedTag == 67)
560  {
562  }
563  if(SpeedTag == 80)
564  {
565  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
566 
567  }
568  if(SpeedTag == 81)
569  {
571  }
572  if(SpeedTag == 82)
573  {
575  }
576  if(SpeedTag == 83)
577  {
579  }
580  if(SpeedTag == 84)
581  {
583  }
584  if(SpeedTag == 85)
585  {
587  }
588  if(SpeedTag == 86)
589  {
591  }
592  if(SpeedTag == 87)
593  {
595  }
596  if(SpeedTag == 129)
597  {
598  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
599 
600  }
601  if(SpeedTag == 130)
602  {
604  }
605  if(XLinkPos == -1) // not set, could be first element or last element = leading point
606  {
607 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
608  if(Link[2] != -1)
609  {
610  return(0); // i.e. complex element, don't display
611  }
612  else
613  {
614  if(!EntryExitNumber())
615  {
616  throw Exception("Error in EntryExitNumber 5");
617  }
618  else
619  {
621  }
622  }
623  }
624  if(EXNumber > 15) // underbridge
625  {
627  }
628  else
629  {
631  }
632 }
633 
634 // ---------------------------------------------------------------------------
635 
636 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
637 /*
638  As above but for route graphics.
639 */
640 {
641  if(!AutoSigsFlag && !PrefDirRoute)
642  {
643  if(SpeedTag == 64)
644  {
645  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
646 
647  }
648  if(SpeedTag == 65)
649  {
651  }
652  if(SpeedTag == 66)
653  {
655  }
656  if(SpeedTag == 67)
657  {
659  }
660  if(SpeedTag == 80)
661  {
662  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
663 
664  }
665  if(SpeedTag == 81)
666  {
668  }
669  if(SpeedTag == 82)
670  {
672  }
673  if(SpeedTag == 83)
674  {
676  }
677  if(SpeedTag == 84)
678  {
680  }
681  if(SpeedTag == 85)
682  {
684  }
685  if(SpeedTag == 86)
686  {
688  }
689  if(SpeedTag == 87)
690  {
692  }
693  if(SpeedTag == 129)
694  {
695  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
696 
697  }
698  if(SpeedTag == 130)
699  {
701  }
702  if(XLinkPos == -1) // not set, could be first element or last element = leading point
703  {
704  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
705  if(Link[2] != -1)
706  {
707  return(0); // i.e. complex element, don't display
708  }
709  else
710  {
711  if(!EntryExitNumber())
712  {
713  throw Exception("Error in EntryExitNumber 6");
714  }
715  else
716  {
718  }
719  }
720  }
721  if(EXNumber > 15) // underbridge
722  {
724  }
725  else
726  {
728  }
729  }
730 
731  else if(!AutoSigsFlag && PrefDirRoute)
732  {
733  if(SpeedTag == 64)
734  {
735  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
736 
737  }
738  if(SpeedTag == 65)
739  {
741  }
742  if(SpeedTag == 66)
743  {
745  }
746  if(SpeedTag == 67)
747  {
749  }
750  if(SpeedTag == 80)
751  {
752  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
753 
754  }
755  if(SpeedTag == 81)
756  {
758  }
759  if(SpeedTag == 82)
760  {
762  }
763  if(SpeedTag == 83)
764  {
766  }
767  if(SpeedTag == 84)
768  {
770  }
771  if(SpeedTag == 85)
772  {
774  }
775  if(SpeedTag == 86)
776  {
778  }
779  if(SpeedTag == 87)
780  {
782  }
783  if(SpeedTag == 129)
784  {
785  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
786 
787  }
788  if(SpeedTag == 130)
789  {
791  }
792  if(XLinkPos == -1) // not set, could be first element or last element = leading point
793  {
794  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
795  if(Link[2] != -1)
796  {
797  return(0); // i.e. complex element, don't display
798  }
799  else
800  {
801  if(!EntryExitNumber())
802  {
803  throw Exception("Error in EntryExitNumber 10");
804  }
805  else
806  {
808  }
809  }
810  }
811  if(EXNumber > 15) // underbridge
812  {
814  }
815  else
816  {
818  }
819  }
820 
821  else
822  {
823  if(SpeedTag == 64)
824  {
825  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
826 
827  }
828  if(SpeedTag == 65)
829  {
831  }
832  if(SpeedTag == 66)
833  {
835  }
836  if(SpeedTag == 67)
837  {
839  }
840  if(SpeedTag == 80)
841  {
842  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
843 
844  }
845  if(SpeedTag == 81)
846  {
848  }
849  if(SpeedTag == 82)
850  {
852  }
853  if(SpeedTag == 83)
854  {
856  }
857  if(SpeedTag == 84)
858  {
860  }
861  if(SpeedTag == 85)
862  {
864  }
865  if(SpeedTag == 86)
866  {
868  }
869  if(SpeedTag == 87)
870  {
872  }
873  if(SpeedTag == 129)
874  {
875  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
876 
877  }
878  if(SpeedTag == 130)
879  {
881  }
882  if(XLinkPos == -1) // not set, could be first element or last element = leading point
883  {
884  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
885  if(Link[2] != -1)
886  {
887  return(0); // i.e. complex element, don't display
888  }
889  else
890  {
891  if(!EntryExitNumber())
892  {
893  throw Exception("Error in EntryExitNumber 11");
894  }
895  else
896  {
898  }
899  }
900  }
901  if(EXNumber > 15) // underbridge
902  {
904  }
905  else
906  {
908  }
909  }
910 }
911 
912 // ---------------------------------------------------------------------------
913 
915 /*
916  As above but for route flashing graphics. (Disused - now combined with above)
917 */
918 {
919  if(SpeedTag == 64)
920  {
921  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
922 
923  }
924  if(SpeedTag == 65)
925  {
927  }
928  if(SpeedTag == 66)
929  {
931  }
932  if(SpeedTag == 67)
933  {
935  }
936  if(SpeedTag == 80)
937  {
938  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
939 
940  }
941  if(SpeedTag == 81)
942  {
944  }
945  if(SpeedTag == 82)
946  {
948  }
949  if(SpeedTag == 83)
950  {
952  }
953  if(SpeedTag == 84)
954  {
956  }
957  if(SpeedTag == 85)
958  {
960  }
961  if(SpeedTag == 86)
962  {
964  }
965  if(SpeedTag == 87)
966  {
968  }
969  if(SpeedTag == 129)
970  {
971  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
972 
973  }
974  if(SpeedTag == 130)
975  {
977  }
978  if(XLinkPos == -1) // not set, could be first element or last element = leading point
979  {
980 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
981  if(Link[2] != -1)
982  {
983  return(0); // i.e. complex element, don't display
984  }
985  else
986  {
987  if(!EntryExitNumber())
988  {
989  throw Exception("Error in EntryExitNumber 7");
990  }
991  else
992  {
994  }
995  }
996  }
997  if(EXNumber > 15) // underbridge
998  {
1000  }
1001  else
1002  {
1004  }
1005 }
1006 
1007 // ---------------------------------------------------------------------------
1008 
1010 /*
1011  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1012 */
1013 {
1014  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1015  {
1017  }
1018  else
1019  {
1020  throw Exception("Error in EntryExitNumber 8");
1021  }
1022 }
1023 
1024 // ---------------------------------------------------------------------------
1025 
1026 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1027 /*
1028  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1029 */
1030 {
1031  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1032  {
1033  if(!AutoSigsFlag && !PrefDirRoute)
1034  {
1036  }
1037  else if(!AutoSigsFlag && PrefDirRoute)
1038  {
1040  }
1041  else
1042  {
1044  }
1045  }
1046  else
1047  {
1048  throw Exception("Error in EntryExitNumber 9");
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 
1055 /*
1056  Set == operator when TrackVectorPosition, ELink & XLink all same
1057 */
1058 {
1059  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1060  {
1061  return(true);
1062  }
1063  else
1064  {
1065  return(false);
1066  }
1067 }
1068 
1069 // ---------------------------------------------------------------------------
1070 
1072 /*
1073  Set != operator when any of TrackVectorPosition, ELink or XLink different
1074 */
1075 {
1076  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1077  {
1078  return(false);
1079  }
1080  else
1081  {
1082  return(true);
1083  }
1084 }
1085 
1086 // ---------------------------------------------------------------------------
1087 // Track functions
1088 // ---------------------------------------------------------------------------
1089 
1090 // ---------------------------------------------------------------------------
1091 
1092 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1093 {
1094  TypeOfRoute = 0;
1095  ReducedTimePenalty = false;
1096  BarrierState = Up;
1097  ChangeDuration = 0.0;
1098  BaseElementSpeedTag = 1;
1099  HLoc = 0;
1100  VLoc = 0;
1101  StartTime = TDateTime(0);
1102 }
1103 
1104 // ---------------------------------------------------------------------------
1105 
1107 {
1108 // CurrentSpeedButtonTag = 0; //not assigned yet
1109 
1110  HLocMin = 2000000000;
1111  VLocMin = 2000000000;
1112  HLocMax = -2000000000;
1113  VLocMax = -2000000000;
1114  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1115  CopyFlag = false; // only true for copying, so names aren't copied
1116 
1117  AnsiString NL = '\n';
1118 
1119  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1120  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1121  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1122  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1123 
1128 
1129  int InternalLinkCheckArray[9][2] =
1130  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1131 
1132 /* array of valid link values for 'old' location and 'new' location, where
1133  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1134 
1135  for(int x = 0; x < 9; x++)
1136  {
1137  for(int y = 0; y < 2; y++)
1138  {
1139  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1140  }
1141  }
1142 
1143 // Platform and default track element values
1144  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1145 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1146  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1147  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1148  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1149  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1150  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1151  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1152  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1153  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1154 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1155 
1156  int HVArray[10][2] =
1157  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1158 
1159  for(int x = 0; x < 10; x++)
1160  {
1161  for(int y = 0; y < 2; y++)
1162  {
1163  LinkHVArray[x][y] = HVArray[x][y];
1164  }
1165  }
1166  TrackFinished = false;
1167 // DistancesSet = false;
1168 
1169  TSigElement TempSigTable[40] = // original four aspect
1170  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1171  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1172 
1173  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1174  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1175 
1178 
1179  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1180  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1181 
1182  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1183  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1184  {75, 4, RailGraphics->gl75}};
1185 
1186  for(int x = 0; x < 40; x++)
1187  {
1188  SigTable[x] = TempSigTable[x];
1189  }
1190 
1191  TSigElement TempSigTableThreeAspect[40] =
1192  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1193  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1194 
1195  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1196  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1197 
1198  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1199  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1200 
1201  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1202  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1203 
1204  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1205  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1206  {75, 4, RailGraphics->gl75}};
1207 
1208  for(int x = 0; x < 40; x++)
1209  {
1210  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1211  }
1212 
1213  TSigElement TempSigTableTwoAspect[40] =
1214  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1215  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1216 
1217  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1218  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1219 
1220  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1221  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1222 
1223  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1224  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1225 
1226  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1227  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1228  {75, 4, RailGraphics->gl75}};
1229 
1230  for(int x = 0; x < 40; x++)
1231  {
1232  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1233  }
1234 
1235  TSigElement TempSigTableGroundSignal[40] =
1239 
1243 
1247 
1251 
1252  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1255 
1256  for(int x = 0; x < 40; x++)
1257  {
1258  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1259  }
1260 
1261 /*
1262  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1263  a single location. These are as follows:-
1264  Directly Adjacent = up, down, left or right - NOT diagonal.
1265  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1266  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1267  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1268 
1269  //t 76
1270  //b 77
1271  //l 78
1272  //r 79
1273  //c 96
1274  //v fb 129
1275  //h fb 130
1276  //v underpass 145
1277  //h underpass 146
1278  //n 131
1279 */
1280 
1281  int Tag76[25][3] =
1282  {{-1, 0, 96}, // c top plat
1283  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1284  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1285  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1286  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1287  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1288  {0, 0, 129}, {0, -1, 145}, // v up
1289  {0, 0, 145}};
1290 
1291  for(int x = 0; x < 25; x++)
1292  {
1293  for(int y = 0; y < 3; y++)
1294  {
1295  Tag76Array[x][y] = Tag76[x][y];
1296  }
1297  }
1298 
1299  int Tag77[25][3] =
1300  {{-1, 0, 96}, // c bot plat
1301  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1302  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1303  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1304  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1305  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1306  {0, 0, 129}, {0, 1, 145}, // v up
1307  {0, 0, 145}};
1308 
1309  for(int x = 0; x < 25; x++)
1310  {
1311  for(int y = 0; y < 3; y++)
1312  {
1313  Tag77Array[x][y] = Tag77[x][y];
1314  }
1315  }
1316 
1317  int Tag78[25][3] =
1318  {{-1, 0, 96}, // c left plat
1319  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1320  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1321  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1322  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1323  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1324  {0, 0, 130}, {-1, 0, 146}, // h up
1325  {0, 0, 146}};
1326 
1327  for(int x = 0; x < 25; x++)
1328  {
1329  for(int y = 0; y < 3; y++)
1330  {
1331  Tag78Array[x][y] = Tag78[x][y];
1332  }
1333  }
1334 
1335  int Tag79[25][3] =
1336  {{-1, 0, 96}, // c right plat
1337  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1338  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1339  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1340  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1341  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1342  {0, 0, 130}, {1, 0, 146}, // h up
1343  {0, 0, 146}};
1344 
1345  for(int x = 0; x < 25; x++)
1346  {
1347  for(int y = 0; y < 3; y++)
1348  {
1349  Tag79Array[x][y] = Tag79[x][y];
1350  }
1351  }
1352 
1353  int Tag96[28][3] =
1354  {{-1, 0, 96}, // c //concourse
1355  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1356  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1357  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1358  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1359  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1360  {0, -1, 129}, {1, 0, 130}, // h fb
1361  {-1, 0, 130}, {0, 1, 145}, // v up
1362  {0, -1, 145}, {1, 0, 146}, // h up
1363  {-1, 0, 146}};
1364 
1365  for(int x = 0; x < 28; x++)
1366  {
1367  for(int y = 0; y < 3; y++)
1368  {
1369  Tag96Array[x][y] = Tag96[x][y];
1370  }
1371  }
1372 
1373  int Tag129[8][3] = // vert fb
1374  {{0, -1, 96}, // c
1375  {0, -1, 77}, // b
1376  {0, -1, 129}, // v fb
1377 
1378  {0, 1, 96}, // c
1379  {0, 1, 76}, // t
1380  {0, 1, 129}, // v fb
1381 
1382  {0, 0, 76}, // t
1383  {0, 0, 77}}; // b
1384 
1385  for(int x = 0; x < 8; x++)
1386  {
1387  for(int y = 0; y < 3; y++)
1388  {
1389  Tag129Array[x][y] = Tag129[x][y];
1390  }
1391  }
1392 
1393  int Tag145[8][3] = // vert up
1394  {{0, -1, 96}, // c
1395  {0, -1, 77}, // b
1396  {0, -1, 145}, // v fb
1397 
1398  {0, 1, 96}, // c
1399  {0, 1, 76}, // t
1400  {0, 1, 145}, // v fb
1401 
1402  {0, 0, 76}, // t
1403  {0, 0, 77}}; // b
1404 
1405  for(int x = 0; x < 8; x++)
1406  {
1407  for(int y = 0; y < 3; y++)
1408  {
1409  Tag145Array[x][y] = Tag145[x][y];
1410  }
1411  }
1412 
1413  int Tag130[8][3] = // hor fb
1414  {{-1, 0, 96}, // c
1415  {-1, 0, 79}, // r
1416  {-1, 0, 130}, // h fb
1417 
1418  {1, 0, 96}, // c
1419  {1, 0, 78}, // l
1420  {1, 0, 130}, // h fb
1421 
1422  {0, 0, 78}, // l
1423  {0, 0, 79}}; // r
1424 
1425  for(int x = 0; x < 8; x++)
1426  {
1427  for(int y = 0; y < 3; y++)
1428  {
1429  Tag130Array[x][y] = Tag130[x][y];
1430  }
1431  }
1432 
1433  int Tag146[8][3] = // hor up
1434  {{-1, 0, 96}, // c
1435  {-1, 0, 79}, // r
1436  {-1, 0, 146}, // h fb
1437 
1438  {1, 0, 96}, // c
1439  {1, 0, 78}, // l
1440  {1, 0, 146}, // h fb
1441 
1442  {0, 0, 78}, // l
1443  {0, 0, 79}}; // r
1444 
1445  for(int x = 0; x < 8; x++)
1446  {
1447  for(int y = 0; y < 3; y++)
1448  {
1449  Tag146Array[x][y] = Tag146[x][y];
1450  }
1451  }
1452 
1453  int Tag131[4][3] =
1454  {{-1, 0, 131}, // n
1455  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1456 
1457  for(int x = 0; x < 4; x++)
1458  {
1459  for(int y = 0; y < 3; y++)
1460  {
1461  Tag131Array[x][y] = Tag131[x][y];
1462  }
1463  }
1464 
1465  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1466  {
1467  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1468  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1469  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1470  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1471  140, 144, 145, 146
1472  };
1473 
1474  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1475  {
1476  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1477  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1478  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1479  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1480  141, 144, 145, 146
1481  };
1482 
1483  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1484  {
1485  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1486  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1487  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1488  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1489  141, 144, 146, 145
1490  };
1491 
1492  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1493  {
1494  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1495  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1496  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1497  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1498  140, 144, 146, 145
1499  };
1500 
1501  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1502  {
1503  FlipArray[x] = InternalFlipArray[x];
1504  MirrorArray[x] = InternalMirrorArray[x];
1505  RotRightArray[x] = InternalRotRightArray[x];
1506  RotLeftArray[x] = InternalRotLeftArray[x];
1507  }
1508 }
1509 
1510 // ---------------------------------------------------------------------------
1512 {
1513 // delete TrackVectorPtr;
1514 // delete FixedTrackArrayPtr;
1515  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1516 
1517  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1518  {
1519  delete UGMIt->second;
1520  UGMIt++;
1521  }
1522  delete GapFlashGreen;
1523  delete GapFlashRed;
1524  // all the rest are cleared by the relevant automatic destructors
1525 }
1526 
1527 // ---------------------------------------------------------------------------
1528 
1530 {
1531  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1532  {
1533 // loc 0 not used, set to bmSolidBgnd
1537 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1557  };
1558 
1559  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1560  {
1561 // loc 0 not used, set to smSolidBgnd
1565 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1584  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1585  };
1586 
1587 // track types
1588  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1589  {
1590  Erase, // 1 0
1591  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1592  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1593  Crossover, Crossover, // 2 15-16
1594  Unused, // 17 (was for text in earlier development) //1 17
1597  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1601  Platform, Platform, Platform, Platform, // 4 76-79
1604  Concourse, // 1 96
1607  Simple, Simple, Simple, Simple, // 4 125-128
1608  FootCrossing, FootCrossing, // 2 129-130
1609  NamedNonStationLocation, // 1 131
1610  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1611  Simple, Simple, Simple, Simple, // 4 140-143
1612  LevelCrossing, // 1 144
1613  FootCrossing, FootCrossing // 2 145 & 146
1614  };
1615 
1616 // links
1617  int Links[FirstUnusedSpeedTagNumber][4] =
1618  {{-1, -1, -1, -1}, // erase element
1619  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1620  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1621 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1622  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1623  {-1, -1, -1, -1}, // unused
1624  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1625  {2, 7, -1, -1}, // simple
1626  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1627 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1628 // (or right diverging if no straight)
1629  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1630  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1631  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1632  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1633  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1634  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1635  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1636  {-1, -1, -1, -1}, // Concourse
1637  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1638  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1639  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1640  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1641  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1642  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1643  {-1, -1, -1, -1}, // NamedNonStationLocation
1644  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1645 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1646  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1647  {-1, -1, -1, -1}, // level crossing
1648  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1649  };
1650 
1652  {{NotSet, NotSet, NotSet, NotSet}, // unused
1656  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1658  {NotSet, NotSet, NotSet, NotSet}, // unused
1662  {Connection, Connection, NotSet, NotSet}, // simple
1666  {Lead, Trail, Lead, Trail}, // points
1668  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1676  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1682  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1691  {Connection, Connection, NotSet, NotSet}, // Arrows
1693  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1695  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1697  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1698  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1699  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1700  };
1701 
1702  for(int x = 0; x < 17; x++)
1703  {
1704  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1705  }
1706  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1707 // 17 was the old text value so don't want any graphics (now disused)
1708  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1709  {
1710  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1711  }
1712 }
1713 
1714 // ---------------------------------------------------------------------------
1715 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1716  ExistingGraphicLoaded(false), Width(16), Height(16)
1717 {
1718  OriginalGraphic = new Graphics::TBitmap;
1719  OriginalGraphic->PixelFormat = pf8bit;
1720  OriginalGraphic->Width = Width;
1721  OriginalGraphic->Height = Height;
1722  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1723 }
1724 
1725 // ---------------------------------------------------------------------------
1726 
1727 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1728  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1729 {
1730  OriginalGraphic = new Graphics::TBitmap;
1731  OriginalGraphic->PixelFormat = pf8bit;
1732  OriginalGraphic->Width = Width;
1733  OriginalGraphic->Height = Height;
1734  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1735 }
1736 
1737 // ---------------------------------------------------------------------------
1738 
1740 {
1741  delete OriginalGraphic;
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1747 {
1748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1749  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1750  VPos = VPosIn;
1751  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1752 
1753  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1754  SourceRect.init(Left, Top, Left + Width, Top + Height);
1755  ScreenSourceSet = true;
1756  Utilities->CallLogPop(422);
1757 }
1758 
1759 // ---------------------------------------------------------------------------
1760 
1762 {
1763  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1764  if(!OverlayLoaded)
1765  {
1766  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1767  }
1768  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1769  {
1770  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1771  }
1772  if(!ScreenSourceSet)
1773  {
1774  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1775  }
1776  if(ExistingGraphicLoaded) // can only call one of the load functions
1777  {
1778  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1779  }
1780  if(OverlayPlotted) // don't load from screen if overlay plotted
1781  {
1782  Utilities->CallLogPop(775);
1783  return;
1784  }
1785  TRect DestRect(0, 0, Width, Height);
1786 
1788  OriginalLoaded = true;
1789  ScreenGraphicLoaded = true;
1790  Utilities->CallLogPop(423);
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1796 /*
1797  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1798 */
1799 {
1800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1801  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1802  if(!OverlayLoaded)
1803  {
1804  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1805  }
1806  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1807  {
1808  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1809  }
1810  if(ScreenGraphicLoaded) // can only call one of the load functions
1811  {
1812  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1813  }
1814  Width = WidthIn;
1815  Height = HeightIn;
1816  OriginalGraphic->Width = Width;
1817  OriginalGraphic->Height = Height;
1818  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1819  VPos += VOffset;
1820  TRect DestRect(0, 0, Width, Height);
1821 
1822  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1823  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1824  OriginalLoaded = true;
1825  ExistingGraphicLoaded = true;
1826  Utilities->CallLogPop(424);
1827 }
1828 
1829 // ---------------------------------------------------------------------------
1830 
1831 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1832 {
1833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1834  OverlayGraphic = Overlay;
1835  OverlayLoaded = true;
1836  Utilities->CallLogPop(425);
1837 }
1838 
1839 // ---------------------------------------------------------------------------
1840 
1842 {
1843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1844  if(!OverlayLoaded)
1845  {
1846  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1847  }
1848  if(!OverlayPlotted)
1849  {
1850  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1851  Disp->Update();
1852  OverlayPlotted = true;
1853  }
1854  Utilities->CallLogPop(426);
1855 }
1856 
1857 // ---------------------------------------------------------------------------
1858 
1860 {
1861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1862  if(OverlayPlotted)
1863  {
1864  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1865  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1866  {
1867  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1868  }
1869  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1870  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1871  OverlayPlotted = false;
1872  }
1873  Utilities->CallLogPop(427);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1881  bool TrackPresent = false;
1882 
1883  if(InactiveTrackVector.size() != 0)
1884  {
1885  Utilities->CallLogPop(1333);
1886  return(false);
1887  }
1888  else if(TrackVector.size() == 0)
1889  {
1890  Utilities->CallLogPop(1334);
1891  return(true);
1892  }
1893  else
1894  {
1895  for(unsigned int x = 0; x < TrackVector.size(); x++)
1896  {
1897  if((TrackVector.at(x).SpeedTag != 0))
1898  {
1899  TrackPresent = true;
1900  }
1901  }
1902  }
1903  Utilities->CallLogPop(1335);
1904  return(!TrackPresent);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1909 bool TTrack::NoActiveTrack(int Caller)
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1912  bool TrackPresent = false;
1913 
1914  if(TrackVector.size() == 0)
1915  {
1916  Utilities->CallLogPop(1582);
1917  return(true);
1918  }
1919  else
1920  {
1921  for(unsigned int x = 0; x < TrackVector.size(); x++)
1922  {
1923  if((TrackVector.at(x).SpeedTag != 0))
1924  {
1925  TrackPresent = true;
1926  }
1927  break;
1928  }
1929  }
1930  Utilities->CallLogPop(1583);
1931  return(!TrackPresent);
1932 }
1933 
1934 // ---------------------------------------------------------------------------
1935 
1936 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1937 {
1938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1939  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1940  TrackEraseSuccessfulFlag = false;
1941 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1942 // since have to match platforms as well as track
1943 // used to set TrackFinished to false if an element erased
1944 
1945  ErasedTrackVectorPosition = -1; // marker for no element erased
1946  AnsiString SName = "", ErrorString;
1948  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1949  TTrackMapIterator TrackMapPtr;
1950  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1951 
1952  if(TrackVector.size() != 0)
1953  {
1954  TrackMapKeyPair.first = HLocInput;
1955  TrackMapKeyPair.second = VLocInput;
1956  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1957  if(TrackMapPtr != TrackMap.end())
1958  {
1959  bool FoundFlag;
1960  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1961  if(FoundFlag) // should find it as it's in the map
1962  {
1963  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1964  {
1965  SName = TrackElementAt(1, VecPos).LocationName;
1966  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1967  if(ErrorString != "")
1968  {
1969  throw Exception(ErrorString + " for EraseTrackElement 1");
1970  }
1971  LocationNameMultiMap.erase(SNIt);
1972  }
1973  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1974  // ensure erase vector element before map element as iterator no longer valid after a map erase
1975  TrackMap.erase(TrackMapPtr);
1976  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1977  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1979  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1980  if(SName != "")
1981  {
1982  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1983  int HPos, VPos;
1984  if(TextHandler->FindText(1, SName, HPos, VPos))
1985  {
1986  if(TextHandler->TextErase(5, HPos, VPos, SName))
1987  {
1988  ;
1989  } // condition not used
1990 
1991  }
1992  }
1993  ErasedTrackVectorPosition = VecPos;
1994  TrackEraseSuccessfulFlag = true;
1995  }
1996  }
1997  }
1998  if(InactiveTrackVector.size() != 0)
1999  {
2000  unsigned int VecPos;
2001  InactiveTrackMapKeyPair.first = HLocInput;
2002  InactiveTrackMapKeyPair.second = VLocInput;
2003  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2004  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2005  {
2006  SName = "";
2007  VecPos = InactiveTrack2MultiMapIterator->second;
2008  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2009  {
2010  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2011  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2012  if(ErrorString != "")
2013  {
2014  throw Exception(ErrorString + " for EraseTrackElement 2A");
2015  }
2016  LocationNameMultiMap.erase(SNIt);
2017  }
2018  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2019  // ensure erase vector element before map element as iterator no longer valid after a map erase
2020  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2021  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2022  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2024  TrackEraseSuccessfulFlag = true;
2025  if(SName != "")
2026  {
2027  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2028  int HPos, VPos;
2029  if(TextHandler->FindText(2, SName, HPos, VPos))
2030  {
2031  if(TextHandler->TextErase(6, HPos, VPos, SName))
2032  {
2033  ;
2034  } // condition not used
2035 
2036  }
2037  }
2038  }
2039  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2040  {
2041  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2042  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2043  {
2044  SName = "";
2045  VecPos = InactiveTrack2MultiMapIterator->second;
2046  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2047  {
2048  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2049  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2050  if(ErrorString != "")
2051  {
2052  throw Exception(ErrorString + " for EraseTrackElement 2B");
2053  }
2054  LocationNameMultiMap.erase(SNIt);
2055  }
2056  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2057  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2058  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2060  if(SName != "")
2061  {
2062  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2063  int HPos, VPos;
2064  if(TextHandler->FindText(3, SName, HPos, VPos))
2065  {
2066  if(TextHandler->TextErase(7, HPos, VPos, SName))
2067  {
2068  ;
2069  } // condition not used
2070 
2071  }
2072  }
2073  }
2074  }
2075  }
2076  if(TrackEraseSuccessfulFlag)
2077  {
2078  CalcHLocMinEtc(2);
2079  SetTrackFinished(false);
2080  }
2081  if(InternalChecks)
2082  {
2083  CheckMapAndTrack(1); // test
2084  CheckMapAndInactiveTrack(1); // test
2085  CheckLocationNameMultiMap(6); // test
2086  }
2087  Utilities->CallLogPop(428);
2088 }
2089 
2090 // ---------------------------------------------------------------------------
2091 
2092 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2093 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2094 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2095 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2096 {
2097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2098  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2099  bool PlatAllowedFlag = false;
2100 
2101  TrackLinkingRequiredFlag = false;
2102 /*
2103  Not erase, that covered separately.
2104  First check if Current SpeedButton assigned, then check if a platform and only
2105  permit if an appropriate trackpiece already there & not a same platform there.
2106  - can't enter a platform without track first.
2107  Then for non-platforms, check if a track piece already present at location &
2108  reject if so.
2109 */
2110 
2111  TLocationNameMultiMapEntry LocationNameEntry;
2112 
2113  LocationNameEntry.first = "";
2114  if(CurrentTag == 0)
2115  {
2116  Utilities->CallLogPop(429);
2117  return; // not assigned yet
2118  }
2119  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2120 
2121  TempTrackElement.HLoc = HLocInput;
2122  TempTrackElement.VLoc = VLocInput;
2123  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2124 // new at version 0.6 - set signal aspect depending on build mode
2125 
2126  if(TempTrackElement.TrackType == SignalPost)
2127  {
2128  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2129  // pasting a SignalPost can only have values 1 to 4
2130  {
2132  {
2133  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2134  }
2136  {
2137  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2138  }
2140  {
2141  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2142  }
2143  else
2144  {
2145  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2146  }
2147  }
2148  else if(Aspect == 1)
2149  {
2150  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2151  }
2152  else if(Aspect == 2)
2153  {
2154  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2155  }
2156  else if(Aspect == 3)
2157  {
2158  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2159  }
2160  else
2161  {
2162  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2163  }
2164  }
2165  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2166  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2167  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2168  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2169 
2170  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2171  {
2173  {
2174  NonStationOrLevelCrossingPresent = true;
2175  }
2176  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2177  {
2178  NonStationOrLevelCrossingPresent = true;
2179  }
2180  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2181  {
2182  PlatformPresent = true;
2183  }
2184  // no need to check IMPair.second since if that exists it is because .first is a platform
2185  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2186  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2187  }
2188 // check platforms
2189  if(TempTrackElement.TrackType == Platform)
2190  {
2191  if(FoundFlag) // active track element already there
2192  {
2193  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2194  {
2195  ;
2196  }
2197  // same platform type already there so above keeps PlatAllowedFlag false
2198  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2199  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2200  {
2201  PlatAllowedFlag = true;
2202  }
2203  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2204  {
2205  PlatAllowedFlag = true;
2206  }
2207  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2208  {
2209  PlatAllowedFlag = true;
2210  }
2211  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2212  {
2213  PlatAllowedFlag = true;
2214  }
2215  if(PlatAllowedFlag)
2216  {
2217  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2218  TrackPush(1, TempTrackElement);
2219  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2220  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2221  // Must be called AFTER TrackPush
2222  // No need to plot the element - Clearand ... called after this function called
2223  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2224  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2225 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2226 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2227 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2228  if(InternalChecks)
2229  {
2230  CheckMapAndInactiveTrack(5); // test
2231  CheckLocationNameMultiMap(4); // test
2232  }
2233  Utilities->CallLogPop(430);
2234  return;
2235  }
2236  } // if(FoundFlag)
2237 
2238  Utilities->CallLogPop(431);
2239  return;
2240  } // if platform
2241 
2242 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2243  if(TempTrackElement.TrackType == NamedNonStationLocation)
2244  {
2245  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2246  (!FoundFlag && !InactiveFoundFlag))
2247  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2248  {
2249  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2250  TrackPush(2, TempTrackElement);
2251  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2252  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2253  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2254  {
2255 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2256 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2257 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2258  }
2259  if(InternalChecks)
2260  {
2261  CheckMapAndInactiveTrack(11); // test
2262  CheckLocationNameMultiMap(12); // test
2263  }
2264  Utilities->CallLogPop(432);
2265  return;
2266  }
2267  else
2268  {
2269  Utilities->CallLogPop(433);
2270  return;
2271  }
2272  }
2273 // check if a level crossing - OK if placed on a plain straight track
2274  if(TempTrackElement.TrackType == LevelCrossing)
2275  {
2276  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2277  {
2278  TrackPush(11, TempTrackElement);
2279  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2280 // no need for reference to LC element as can't be open
2281  TrackLinkingRequiredFlag = true;
2282  Utilities->CallLogPop(1907);
2283  return;
2284  }
2285  else
2286  {
2287  Utilities->CallLogPop(1906);
2288  return; // was a level crossing but can't place it for some reason
2289  }
2290  }
2291 
2292 // check if another element already there
2293  else if(FoundFlag || InactiveFoundFlag)
2294  {
2295  Utilities->CallLogPop(434);
2296  return; // something already there (active or inactive track)
2297  }
2298 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2299 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2300 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2301 // do this after pushed into vector so that can use EnterLocationName
2302 
2303  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2304  {
2305  TrackPush(3, TempTrackElement);
2306  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2307  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2308  }
2309  else if(TempTrackElement.TrackType == Points)
2310  {
2311  TrackPush(4, TempTrackElement);
2312  bool BothPointFillets = true;
2313  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2314  }
2315  else if(TempTrackElement.TrackType == SignalPost)
2316  {
2317  TrackPush(10, TempTrackElement);
2318  PlotSignal(12, TempTrackElement, Display);
2319  }
2320  else
2321  {
2322  TrackPush(5, TempTrackElement);
2323  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2324  }
2325  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2326  {
2327  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2328  }
2329  if(InternalChecks)
2330  {
2331  CheckMapAndTrack(2); // test
2332  CheckMapAndInactiveTrack(2); // test
2333  CheckLocationNameMultiMap(5); // test
2334  }
2335  Utilities->CallLogPop(2062);
2336 }
2337 
2338 // ---------------------------------------------------------------------------
2339 
2340 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2341  bool InternalChecks)
2342 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2343 {
2344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2345  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2346  bool PlatAllowedFlag = false;
2347 
2348  TrackLinkingRequiredFlag = false;
2349  TLocationNameMultiMapEntry LocationNameEntry;
2350 
2351  LocationNameEntry.first = "";
2352  if(TempTrackElement.SpeedTag == 0)
2353  {
2354  Utilities->CallLogPop(2063);
2355  return; // not assigned yet
2356  }
2357  TempTrackElement.HLoc = HLocInput;
2358  TempTrackElement.VLoc = VLocInput;
2359  for(int x = 0; x < 4; x++) // unset any gaps
2360  {
2361  if(TempTrackElement.Config[x] == Gap)
2362  {
2363  TempTrackElement.ConnLinkPos[x] = -1;
2364  }
2365  TempTrackElement.Conn[x] = -1;
2366  }
2367  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2368 // new at version 0.6 - set signal aspect depending on build mode
2369  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2370  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2371 
2372  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2373  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2374  // for the active track element because these aren't set
2375  // if don't do this then get a mismatch error during map checks later
2376 
2377  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2378 
2379  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2380  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2381 
2382  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2383  {
2384  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2385  {
2386  NonStationOrLevelCrossingPresent = true;
2387  }
2388  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2389  {
2390  NonStationOrLevelCrossingPresent = true;
2391  }
2392  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2393  {
2394  PlatformPresent = true;
2395  }
2396  // no need to check IMPair.second since if that exists it is because .first is a platform
2397  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2398  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2399  }
2400 // check platforms
2401  if(TempTrackElement.TrackType == Platform)
2402  {
2403  if(FoundFlag) // active track element already there
2404  {
2405  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2406  {
2407  ;
2408  }
2409  // same platform type already there so above keeps PlatAllowedFlag false
2410  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2411  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2412  {
2413  PlatAllowedFlag = true;
2414  }
2415  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2416  {
2417  PlatAllowedFlag = true;
2418  }
2419  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2420  {
2421  PlatAllowedFlag = true;
2422  }
2423  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2424  {
2425  PlatAllowedFlag = true;
2426  }
2427  if(PlatAllowedFlag)
2428  {
2429  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2430  TrackPush(12, TempTrackElement);
2431 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2432  {
2433  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2434  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2435  }
2436  // Must be called AFTER TrackPush
2437 // No need to plot the element - Clearand ... called after this function called
2438  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2439  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2440 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2441 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2442 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2443  if(InternalChecks)
2444  {
2445  CheckMapAndInactiveTrack(12); // test
2446  CheckLocationNameMultiMap(20); // test
2447  }
2448  Utilities->CallLogPop(2064);
2449  return;
2450  }
2451  } // if(FoundFlag)
2452 
2453  Utilities->CallLogPop(2065);
2454  return;
2455  } // if platform
2456 
2457 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2458  if(TempTrackElement.TrackType == NamedNonStationLocation)
2459  {
2460  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2461  (!FoundFlag && !InactiveFoundFlag))
2462  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2463  {
2464  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2465  TrackPush(13, TempTrackElement);
2466 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2467  {
2468  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2469  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2470  }
2471  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2472  {
2473 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2474 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2475 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2476  }
2477  if(InternalChecks)
2478  {
2479  CheckMapAndInactiveTrack(13); // test
2480  CheckLocationNameMultiMap(21); // test
2481  }
2482  Utilities->CallLogPop(2066);
2483  return;
2484  }
2485  else
2486  {
2487  Utilities->CallLogPop(2067);
2488  return;
2489  }
2490  }
2491 // check if a level crossing - OK if placed on a plain straight track
2492  if(TempTrackElement.TrackType == LevelCrossing)
2493  {
2494  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2495  {
2496  TrackPush(14, TempTrackElement);
2497  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2498 // no need for reference to LC element as can't be open
2499  TrackLinkingRequiredFlag = true;
2500  Utilities->CallLogPop(2068);
2501  return;
2502  }
2503  else
2504  {
2505  Utilities->CallLogPop(2069);
2506  return; // was a level crossing but can't place it for some reason
2507  }
2508  }
2509 
2510 // check if another element already there
2511  else if(FoundFlag || InactiveFoundFlag)
2512  {
2513  Utilities->CallLogPop(2070);
2514  return; // something already there (active or inactive track)
2515  }
2516 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2517 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2518 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2519 // do this after pushed into vector so that can use EnterLocationName
2520 
2521  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2522  {
2523  TrackPush(15, TempTrackElement);
2524  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2525  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2526  }
2527  else if(TempTrackElement.TrackType == Points)
2528  {
2529  TrackPush(16, TempTrackElement);
2530  bool BothPointFillets = true;
2531  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2532  }
2533  else if(TempTrackElement.TrackType == SignalPost)
2534  {
2535  TrackPush(17, TempTrackElement);
2536  PlotSignal(14, TempTrackElement, Display);
2537  }
2538  else
2539  {
2540  TrackPush(18, TempTrackElement);
2541  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2542  }
2543  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2544  {
2545  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2546  }
2547  if(InternalChecks)
2548  {
2549  CheckMapAndTrack(12); // test
2550  CheckMapAndInactiveTrack(14); // test
2551  CheckLocationNameMultiMap(22); // test
2552  }
2553  Utilities->CallLogPop(2071);
2554 }
2555 
2556 // ---------------------------------------------------------------------------
2557 
2558 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2559 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2560 // return bool = true for success
2561 // LocError = true for location error & HLoc & VLoc to be inverted
2562 {
2563  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2564  LocError = false;
2565  SetTrackFinished(false);
2566  if(TrackVector.size() == 0)
2567  {
2568  Utilities->CallLogPop(437);
2569  return(false);
2570  }
2571  if(GapsUnset(7))
2572  {
2573  if(GiveMessages)
2574  {
2575  ShowMessage("Gaps must be set before track can be validated");
2576  }
2577  Utilities->CallLogPop(1135);
2578  return(false);
2579  }
2580 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2581 // returns true for any unset gaps
2583  {
2584  // can keep this exception as protected by the GapsUnset call above
2585  throw Exception("Error, gaps unset when TryToConnectTrack called");
2586  }
2588  CheckGapMap(1); // test
2589 // Gap connections now securely defined
2590 
2591  CheckMapAndTrack(8); // test
2592 
2593 // Perform a pre-check prior to TrackMap being compiled
2594  if(GiveMessages)
2595  {
2596  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2597  {
2598  Utilities->CallLogPop(439);
2599  return(false);
2600  }
2601  }
2602  else
2603  {
2604  if(!LinkTrackNoMessages(1, false))
2605  {
2606  Utilities->CallLogPop(1131);
2607  return(false);
2608  }
2609  }
2610 // here if pre-check successful
2611  if(!RepositionAndMapTrack(0))
2612  {
2613  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2614  Utilities->CallLogPop(1138);
2615  return(false);
2616  }
2617 // now perform the final assembly - FinalCall = true
2618  if(GiveMessages)
2619  {
2620  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2621  {
2622  Utilities->CallLogPop(1116);
2623  return(false);
2624  }
2625  }
2626  else
2627  {
2628  if(!LinkTrackNoMessages(2, true))
2629  {
2630  Utilities->CallLogPop(1132);
2631  return(false);
2632  }
2633  }
2634 // success
2635 
2636  PopulateLCVector(0);
2637  CheckGapMap(2); // test
2638  CheckMapAndTrack(3); // test
2639  CheckMapAndInactiveTrack(3); // test
2640  CheckLocationNameMultiMap(9); // test
2641  SetTrackFinished(true);
2642 
2643 // Build ContinuationNameMap
2644  std::pair<AnsiString, char>TempMapPair;
2645 
2646  ContinuationNameMap.clear();
2647  for(int x = 0; x < Track->TrackVectorSize(); x++)
2648  {
2649  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2650  {
2651  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2652  TempMapPair.second = 'x'; // unused
2653  ContinuationNameMap.insert(TempMapPair);
2654  }
2655  }
2656  Utilities->CallLogPop(440);
2657  return(true);
2658 }
2659 
2660 // ---------------------------------------------------------------------------
2661 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2662 // unused - too time-consuming - double brute force search
2663 {
2664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2665  int NewHLoc, NewVLoc;
2666  bool ConnectionFoundFlag, LinkFoundFlag;
2667 
2668  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2669  {
2670  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2671  {
2672  if(TrackVector.at(x).Link[y] <= 0)
2673  {
2674  continue; // no link
2675  }
2676  if(TrackVector.at(x).Config[y] == End)
2677  {
2678  continue; // buffer or continuation
2679  }
2680  if(TrackVector.at(x).Config[y] == Gap)
2681  {
2682  continue; // gap jump
2683  }
2684  // get required H & V for track element joining link 'y'
2685  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2686  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2687  // find track element if present
2688  ConnectionFoundFlag = false;
2689  for(unsigned int z = 0; z < TrackVector.size(); z++)
2690  {
2691 // if(TrackElementAt(5, z).TrackType == Platform)
2692 // continue; //skip platforms
2693  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2694  {
2695  ConnectionFoundFlag = true;
2696  // find connecting link in the newly found track element if there is one
2697  LinkFoundFlag = false;
2698  for(unsigned int a = 0; a < 4; a++)
2699  {
2700  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2701  {
2702  LinkFoundFlag = true;
2703  }
2704  }
2705  // if there isn't a corresponding link set the invert values for the offending element
2706  if(!LinkFoundFlag)
2707  {
2708  HLoc = TrackVector.at(x).HLoc;
2709  VLoc = TrackVector.at(x).VLoc;
2710  Utilities->CallLogPop(441);
2711  return(true);
2712  }
2713  break; // success, so break out of 'z' loop
2714  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2715 
2716  } // for z...
2717  // if there isn't a connection set the invert values for the offending element
2718  if(!ConnectionFoundFlag)
2719  {
2720  HLoc = TrackVector.at(x).HLoc;
2721  VLoc = TrackVector.at(x).VLoc;
2722  Utilities->CallLogPop(442);
2723  return(true);
2724  }
2725  } // for y....
2726  } // for x...
2727  Utilities->CallLogPop(443);
2728  return(false); // all OK
2729 }
2730 
2731 // ---------------------------------------------------------------------------
2732 
2733 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2734 {
2735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2736  TrackElement.LogTrack(0));
2737  bool FoundFlag;
2738 
2739  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2740  if(FoundFlag)
2741  {
2742  TrackElement = TrackVector.at(Position);
2743  }
2744  Utilities->CallLogPop(444);
2745  return(FoundFlag);
2746 }
2747 
2748 // ---------------------------------------------------------------------------
2749 
2751 {
2752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2753  if(NextTrackElementPtr >= TrackVector.end())
2754  {
2755  Utilities->CallLogPop(1336);
2756  return(false);
2757  }
2758  Next = *NextTrackElementPtr;
2760  Utilities->CallLogPop(1337);
2761  return(true);
2762 }
2763 
2764 // ---------------------------------------------------------------------------
2765 
2767 {
2768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2770  {
2771  Utilities->CallLogPop(1338);
2772  return(false);
2773  }
2774  Next = *NextTrackElementPtr;
2776  Utilities->CallLogPop(1339);
2777  return(true);
2778 }
2779 
2780 // ---------------------------------------------------------------------------
2781 
2782 int TTrack::NumberOfGaps(int Caller)
2783 
2784 {
2785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2786  int Count = 0;
2787 
2788  if(TrackVector.size() == 0)
2789  {
2790  Utilities->CallLogPop(1340);
2791  return(0);
2792  }
2793  for(unsigned int x = 0; x < TrackVector.size(); x++)
2794  {
2795  if(TrackVector.at(x).TrackType == GapJump)
2796  {
2797  Count++;
2798  }
2799  }
2800  Utilities->CallLogPop(1341);
2801  return(Count);
2802 }
2803 
2804 // ---------------------------------------------------------------------------
2806 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2807 // returns true for any unset gaps
2808 {
2809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2810  bool UnsetGaps = false;
2811 
2812  if(TrackVector.size() == 0)
2813  {
2814  Utilities->CallLogPop(445);
2815  return(false);
2816  }
2817  for(unsigned int x = 0; x < TrackVector.size(); x++)
2818  {
2819  if(TrackVector.at(x).TrackType != GapJump)
2820  {
2821  for(unsigned int y = 0; y < 4; y++)
2822  {
2823  TrackVector.at(x).Conn[y] = -1;
2824  TrackVector.at(x).ConnLinkPos[y] = -1;
2825  }
2826  }
2827  else // GapJump
2828  {
2829 // int tempint = TrackVector.at(x).Conn[0);
2830 
2831  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2832  {
2833  for(unsigned int y = 0; y < 4; y++)
2834  {
2835  TrackVector.at(x).Conn[y] = -1;
2836  TrackVector.at(x).ConnLinkPos[y] = -1;
2837  }
2838  UnsetGaps = true;
2839  continue; // to next 'x'
2840  }
2841  else // set, but may not have matching element, or that element may not be set
2842  {
2843  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2844  {
2845  TrackVector.at(x).Conn[y] = -1;
2846  TrackVector.at(x).ConnLinkPos[y] = -1;
2847  }
2848 
2849  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2850  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2851  {
2852  for(unsigned int y = 0; y < 4; y++)
2853  {
2854  TrackVector.at(x).Conn[y] = -1;
2855  TrackVector.at(x).ConnLinkPos[y] = -1;
2856  }
2857  UnsetGaps = true;
2858  continue; // to next 'x'
2859  }
2860 // here if gap connection is itself a GapJump
2861  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2862  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2863  // if not clear Conns & CLks & reset Lk[0]
2864  {
2865  for(unsigned int y = 0; y < 4; y++)
2866  {
2867  TrackVector.at(x).Conn[y] = -1;
2868  TrackVector.at(x).ConnLinkPos[y] = -1;
2869  }
2870  UnsetGaps = true;
2871  continue; // to next 'x'
2872  }
2873 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2874 // hence no more action needed on these Conns & CLks
2875  }
2876  } // else //gap jump
2877 
2878  } // for x...
2879  Utilities->CallLogPop(446);
2880  return(UnsetGaps);
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2886 {
2887 // VecFile already open and its pointer at right place on calling
2888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2889  int TempInt;
2890 
2891  TrackClear(1);
2892 // load track elements
2893  int NumberOfActiveElements = 0;
2894 
2895  GraphicsFollow = false;
2896  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2897  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2898 
2899  if(MarkerString[MarkerString.Length()] == '1')
2900  {
2901  GraphicsFollow = true;
2902  }
2903  for(int x = 0; x < NumberOfActiveElements; x++)
2904  {
2905  VecFile >> TempInt; // TrackVectorNumber, not used
2906  VecFile >> TempInt; // SpeedTag
2907  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2908  VecFile >> TempInt;
2909  TrackElement.HLoc = TempInt;
2910  VecFile >> TempInt;
2911  TrackElement.VLoc = TempInt;
2912  if(TrackElement.TrackType == GapJump)
2913  {
2914  VecFile >> TempInt;
2915  TrackElement.ConnLinkPos[0] = TempInt;
2916  VecFile >> TempInt;
2917  TrackElement.Conn[0] = TempInt;
2918  }
2919  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2920  {
2921  VecFile >> TempInt;
2922  TrackElement.Attribute = TempInt;
2923  }
2924  if(TrackElement.TrackType == SignalPost)
2925  {
2926  VecFile >> TempInt;
2927  if(TempInt == 0)
2928  {
2929  TrackElement.CallingOnSet = false;
2930  }
2931  else
2932  {
2933  TrackElement.CallingOnSet = true;
2934  }
2935  }
2936  VecFile >> TempInt;
2937  TrackElement.Length01 = TempInt;
2938  VecFile >> TempInt;
2939  TrackElement.Length23 = TempInt;
2940  VecFile >> TempInt;
2941  if((TempInt != -1) && (TempInt < 10))
2942  {
2943  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2944  }
2945  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2946  {
2947  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2948  }
2949  TrackElement.SpeedLimit01 = TempInt;
2950  VecFile >> TempInt;
2951  if((TempInt != -1) && (TempInt < 10))
2952  {
2953  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2954  }
2955  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2956  {
2957  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2958  }
2959  TrackElement.SpeedLimit23 = TempInt;
2960 
2961  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2962  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2963  SetElementID(0, TrackElement);
2964  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2965 // new for v0.6
2966  if(TrackElement.TrackType == SignalPost)
2967  {
2968  if(Marker[1] == '3')
2969  {
2970  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2971  }
2972  else if(Marker[1] == '2')
2973  {
2974  TrackElement.SigAspect = TTrackElement::TwoAspect;
2975  }
2976  else if(Marker[1] == 'G')
2977  {
2978  TrackElement.SigAspect = TTrackElement::GroundSignal;
2979  }
2980  else
2981  {
2982  TrackElement.SigAspect = TTrackElement::FourAspect;
2983  }
2984  }
2985  if(TrackElement.SpeedTag != 0)
2986  {
2987  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2988  }
2989  }
2990  int NumberOfInactiveElements = 0;
2991 
2992  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2993  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2994  for(int x = 0; x < NumberOfInactiveElements; x++)
2995  {
2996  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3004  SetElementID(3, TrackElement);
3005  TrackPush(9, TrackElement);
3006  Utilities->LoadFileString(VecFile); // marker
3007  }
3008  bool LocError = false; // needed for TryToConnectTrack but not used
3009  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3010 
3011  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3012  {
3013  SetTrackFinished(true);
3014  }
3015  else
3016  {
3017  SetTrackFinished(false);
3018  }
3019 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3020 // CheckMapAndInactiveTrack(8);
3021 // CheckLocationNameMultiMap(10);
3022  Utilities->CallLogPop(448);
3023 }
3024 
3025 // ---------------------------------------------------------------------------
3026 
3027 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3028 {
3029 // VecFile already open and its pointer at right place on calling
3030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3031 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3032 // & load into UserGraphicItem then store in UserGraphicVector
3033  UserGraphicVector.clear();
3034  TUserGraphicItem UGI;
3035  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3036 
3037  for(int x = 0; x < NumberOfGraphics; x++)
3038  {
3039  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3040  UGI.HPos = Utilities->LoadFileInt(VecFile);
3041  UGI.VPos = Utilities->LoadFileInt(VecFile);
3042  UGI.Width = 0; // provisional value
3043  UGI.Height = 0; // provisional value
3044  UGI.UserGraphic = NULL; // provisional value
3045  UserGraphicVector.push_back(UGI);
3046  }
3047 // now load the map & set Width, Height & TPicture*
3048  bool FileError = false;
3049 
3050  for(int x = 0; x < NumberOfGraphics; x++)
3051  {
3052  if(FileError)
3053  {
3054  break; // otherwise keeps going round the loop
3055  }
3056  UGI = UserGraphicVectorAt(0, x);
3057  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3058  {
3059  try
3060  {
3061 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3062  UGME.first = UGI.FileName;
3063  UGME.second = new TPicture;
3064  UGME.second->LoadFromFile(UGME.first); // errors caught below
3065  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3066  {
3067  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3068  }
3069  UGI.UserGraphic = UGME.second;
3070  UGI.Width = UGI.UserGraphic->Width;
3071  UGI.Height = UGI.UserGraphic->Height;
3072  UserGraphicVectorAt(1, x) = UGI;
3073  }
3074  catch(const EInvalidGraphic &e) //non error catch
3075  {
3076  //message already sent in CheckUserGraphics
3077  FileError = true;
3078  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3079  if(!UserGraphicMap.empty())
3080  {
3081  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3082  {
3083  delete UGMIt->second;
3084  }
3085  UserGraphicMap.clear();
3086  }
3087  }
3088  catch(const Exception &e) //non error catch
3089  {
3090  //message already sent in CheckUserGraphics
3091  FileError = true;
3092  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3093  if(!UserGraphicMap.empty())
3094  {
3095  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3096  {
3097  delete UGMIt->second;
3098  }
3099  UserGraphicMap.clear();
3100  }
3101  }
3102  }
3103  else
3104  {
3105  bool FoundInMap = false;
3106  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3107  {
3108  if(UGI.FileName == UGMIt->first) // already exists in map
3109  {
3110  UGI.UserGraphic = UGMIt->second;
3111  UGI.Width = UGI.UserGraphic->Width;
3112  UGI.Height = UGI.UserGraphic->Height;
3113  UserGraphicVectorAt(2, x) = UGI;
3114  FoundInMap = true;
3115  break;
3116  }
3117  }
3118  if(!FoundInMap)
3119  {
3120  try
3121  {
3123  UGME.first = UGI.FileName;
3124  UGME.second = new TPicture;
3125  UGME.second->LoadFromFile(UGME.first); // errors caught below
3126  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3127  {
3128  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3129  }
3130  UGI.UserGraphic = UGME.second;
3131  UGI.Width = UGI.UserGraphic->Width;
3132  UGI.Height = UGI.UserGraphic->Height;
3133  UserGraphicVectorAt(3, x) = UGI;
3134  }
3135  catch(const EInvalidGraphic &e) //non error catch
3136  {
3137  //message already sent in CheckUserGraphics
3138  FileError = true;
3139  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3140  if(!UserGraphicMap.empty())
3141  {
3142  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3143  {
3144  delete UGMIt->second;
3145  }
3146  UserGraphicMap.clear();
3147  }
3148  }
3149  catch(const Exception &e) //non error catch
3150  {
3151  //message already sent in CheckUserGraphics
3152  FileError = true;
3153  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3154  if(!UserGraphicMap.empty())
3155  {
3156  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3157  {
3158  delete UGMIt->second;
3159  }
3160  UserGraphicMap.clear();
3161  }
3162  }
3163  }
3164  }
3165  }
3166  Utilities->CallLogPop(2167);
3167 }
3168 
3169 // ---------------------------------------------------------------------------
3170 
3171 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3172 {
3173 // VecFile already open and its pointer at right place on calling
3174 // if GraphicsFollow true, then save Marker as **Active elements**1
3175 // save trackfinished flag
3176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3177  TTrackElement TrackElement, InactiveTrackElement;
3178 
3179 // save track elements
3180  Utilities->SaveFileInt(VecFile, TrackVector.size());
3181  if(GraphicsFollow)
3182  {
3183  VecFile << "**Active elements**1" << '\0' << '\n';
3184  }
3185  else
3186  {
3187  VecFile << "**Active elements**" << '\0' << '\n';
3188  }
3189  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3190  {
3191  TrackElement = TrackVector.at(x);
3192  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3193  VecFile << TrackElement.SpeedTag << '\n';
3194  VecFile << TrackElement.HLoc << '\n';
3195  VecFile << TrackElement.VLoc << '\n';
3196  if(TrackElement.TrackType == GapJump)
3197  {
3198  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3199  VecFile << TrackElement.Conn[0] << '\n';
3200  }
3201  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3202  {
3203  VecFile << TrackElement.Attribute << '\n';
3204  }
3205  if(TrackElement.TrackType == SignalPost)
3206  {
3207  if(TrackElement.CallingOnSet)
3208  {
3209  VecFile << int(1) << '\n';
3210  }
3211  else
3212  {
3213  VecFile << int(0) << '\n';
3214  }
3215  }
3216  VecFile << TrackElement.Length01 << '\n';
3217  VecFile << TrackElement.Length23 << '\n';
3218  VecFile << TrackElement.SpeedLimit01 << '\n';
3219  VecFile << TrackElement.SpeedLimit23 << '\n';
3220  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3221  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3222 // new for v0.6
3223  if(TrackElement.TrackType == SignalPost)
3224  {
3225  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3226  {
3227  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3228  }
3229  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3230  {
3231  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3232  }
3233  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3234  {
3235  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3236  }
3237  else // 4 aspect
3238  {
3239  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3240  }
3241  }
3242  else
3243  {
3244  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3245  }
3246  }
3247 
3248  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3249  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3250  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3251  {
3252  InactiveTrackElement = InactiveTrackVector.at(x);
3253  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3254  VecFile << InactiveTrackElement.SpeedTag << '\n';
3255  VecFile << InactiveTrackElement.HLoc << '\n';
3256  VecFile << InactiveTrackElement.VLoc << '\n';
3257  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3258  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3259  }
3260  Utilities->CallLogPop(449);
3261 }
3262 
3263 // ---------------------------------------------------------------------------
3264 
3265 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3266 {
3267 // VecFile already open and its pointer at right place on calling
3268 // check trackfinished flag
3269 // inactive elements follow immediately after active elements, no need to check for a marker between them
3270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3271  int TempInt;
3272 
3273  GraphicsFollow = false;
3274  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3275  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3276  {
3277  Utilities->CallLogPop(1513);
3278  return(false);
3279  }
3280 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3281  AnsiString MarkerString;
3282 
3283  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3284  {
3285  Utilities->CallLogPop(1758);
3286  return(false);
3287  }
3288  if(MarkerString[MarkerString.Length()] == '1')
3289  {
3290  GraphicsFollow = true;
3291  }
3292  for(int x = 0; x < NumberOfActiveElements; x++)
3293  {
3294  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3295  {
3296  Utilities->CallLogPop(1759);
3297  return(false);
3298  }
3299  VecFile >> TempInt;
3300  int SpeedTag = TempInt;
3301  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3302  {
3303  Utilities->CallLogPop(1514);
3304  return(false);
3305  }
3306  VecFile >> TempInt;
3307  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3308  {
3309  Utilities->CallLogPop(1495);
3310  return(false);
3311  }
3312  VecFile >> TempInt;
3313  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3314  {
3315  Utilities->CallLogPop(1497);
3316  return(false);
3317  }
3318  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3319  {
3320  VecFile >> TempInt;
3321  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3322  {
3323  Utilities->CallLogPop(1499);
3324  return(false);
3325  }
3326  VecFile >> TempInt;
3327  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3328  {
3329  Utilities->CallLogPop(1500);
3330  return(false);
3331  }
3332  }
3333  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3334  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3335  {
3336  VecFile >> TempInt;
3337  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3338  {
3339  Utilities->CallLogPop(1502);
3340  return(false);
3341  }
3342  }
3343  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3344  {
3345  VecFile >> TempInt;
3346  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3347  {
3348  Utilities->CallLogPop(1155);
3349  return(false);
3350  }
3351  }
3352  VecFile >> TempInt;
3353  if((TempInt < -1) || (TempInt > 999999)) // Length01
3354  {
3355  Utilities->CallLogPop(1503);
3356  return(false);
3357  }
3358  VecFile >> TempInt;
3359  if((TempInt < -1) || (TempInt > 999999)) // Length23
3360  {
3361  Utilities->CallLogPop(1504);
3362  return(false);
3363  }
3364  VecFile >> TempInt;
3365  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3366  {
3367  Utilities->CallLogPop(1505);
3368  return(false);
3369  }
3370  VecFile >> TempInt;
3371  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3372  {
3373  Utilities->CallLogPop(1506);
3374  return(false);
3375  }
3376  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3377  {
3378  Utilities->CallLogPop(1142);
3379  return(false); // LocationName
3380  }
3381  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3382  {
3383  Utilities->CallLogPop(1143);
3384  return(false); // ActiveTrackElementName
3385  }
3386  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3387  {
3388  Utilities->CallLogPop(1787);
3389  return(false); // marker
3390  }
3391  }
3392  int NumberOfInactiveElements = 0;
3393 
3394  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3395  if(NumberOfInactiveElements < 0) // No of active elements
3396  {
3397  Utilities->CallLogPop(1493);
3398  return(false);
3399  }
3400  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3401  {
3402  Utilities->CallLogPop(1764);
3403  return(false); // **Inactive elements** marker
3404  }
3405  for(int x = 0; x < NumberOfInactiveElements; x++)
3406  {
3407  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3408  {
3409  Utilities->CallLogPop(1765);
3410  return(false);
3411  }
3412  VecFile >> TempInt;
3413  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3414  {
3415  Utilities->CallLogPop(1494);
3416  return(false);
3417  }
3418  VecFile >> TempInt;
3419  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3420  {
3421  Utilities->CallLogPop(1496);
3422  return(false);
3423  }
3424  VecFile >> TempInt;
3425  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3426  {
3427  Utilities->CallLogPop(1498);
3428  return(false);
3429  }
3430  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3431  {
3432  Utilities->CallLogPop(1144);
3433  return(false); // LocationName
3434  }
3435  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3436  {
3437  Utilities->CallLogPop(1788);
3438  return(false); // marker
3439  }
3440  }
3441  Utilities->CallLogPop(1507);
3442  return(true);
3443 }
3444 
3445 // ---------------------------------------------------------------------------
3446 
3447 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3448 {
3449  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3450  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3451 
3452  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3453  {
3454  Utilities->CallLogPop(2168);
3455  return(false);
3456  }
3457  // filename in Graphics folder, then HPos, then VPos
3458  AnsiString FileName = "", TempStr = "";
3459 
3460  for(int x = 0; x < NumberOfGraphics; x++)
3461  {
3462  TPicture *TempPicture = new TPicture;
3463  try
3464  {
3465  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3466  {
3467  Utilities->CallLogPop(2169);
3468  delete TempPicture;
3469  return(false);
3470  }
3471  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3472  delete TempPicture;
3473  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3474  {
3475  Utilities->CallLogPop(2170);
3476  return(false);
3477  }
3478  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3479  {
3480  Utilities->CallLogPop(2171);
3481  return(false);
3482  }
3483  }
3484  catch(const EInvalidGraphic &e) //non error catch
3485  {
3486  //move file pointer to end of graphic section for later checks in session files
3487  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3488  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3489  for(int y = x + 1; y < NumberOfGraphics; y++)
3490  {
3491  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3492  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3493  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3494  }
3495  ShowMessage(FileName +
3496  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3497  Utilities->CallLogPop(2172);
3498  delete TempPicture;
3499  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3500  }
3501  catch(const Exception &e) //non error catch
3502  {
3503  //move file pointer to end of graphic section for later checks in session files
3504  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3505  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3506  for(int y = x + 1; y < NumberOfGraphics; y++)
3507  {
3508  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3509  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3510  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3511  }
3512  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3513  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3514  Utilities->CallLogPop(2173);
3515  delete TempPicture;
3516  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3517  }
3518  }
3519  Utilities->CallLogPop(2174);
3520  return(true);
3521 }
3522 
3523 // ---------------------------------------------------------------------------
3524 
3525 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3526 {
3527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3528  int VecSize = Track->BarriersDownVector.size();
3529 
3530  Utilities->SaveFileInt(OutFile, VecSize);
3531  for(int x = 0; x < VecSize; x++)
3532  {
3534  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3535  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3536  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3537  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3538  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3539  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3540  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3541  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3542  }
3543  Utilities->CallLogPop(1963);
3544 }
3545 
3546 // ---------------------------------------------------------------------------
3547 
3548 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3549 {
3550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3551  int VecSize = Track->ChangingLCVector.size();
3552 
3553  Utilities->SaveFileInt(OutFile, VecSize);
3554  for(int x = 0; x < VecSize; x++)
3555  {
3557  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3558  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3559  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3560  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3561  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3562  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3563  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3564  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3565  }
3566  Utilities->CallLogPop(1980);
3567 }
3568 
3569 // ---------------------------------------------------------------------------
3570 
3571 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3572 {
3573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3574  int VecSize = Utilities->LoadFileInt(VecFile);
3575 
3576  for(int x = 0; x < VecSize; x++)
3577  {
3578  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3579  {
3580  Utilities->CallLogPop(1970);
3581  return(false);
3582  }
3583  if(!Utilities->CheckFileBool(VecFile))
3584  {
3585  Utilities->CallLogPop(1971);
3586  return(false);
3587  }
3588  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3589  {
3590  Utilities->CallLogPop(1972);
3591  return(false);
3592  }
3593  if(!Utilities->CheckFileDouble(VecFile))
3594  {
3595  Utilities->CallLogPop(1973);
3596  return(false);
3597  }
3598  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3599  {
3600  Utilities->CallLogPop(1974);
3601  return(false);
3602  }
3603  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3604  {
3605  Utilities->CallLogPop(1975);
3606  return(false);
3607  }
3608  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3609  {
3610  Utilities->CallLogPop(1976);
3611  return(false);
3612  }
3613  if(!Utilities->CheckFileDouble(VecFile))
3614  {
3615  Utilities->CallLogPop(1977);
3616  return(false);
3617  }
3618  }
3619  Utilities->CallLogPop(1978);
3620  return(true);
3621 }
3622 
3623 // ---------------------------------------------------------------------------
3624 
3625 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3626 {
3627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3628  int VecSize = Utilities->LoadFileInt(VecFile);
3629 
3630  for(int x = 0; x < VecSize; x++)
3631  {
3632  TActiveLevelCrossing TALC;
3633  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3634  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3635  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3636  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3637  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3638  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3639  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3640  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3641  BarriersDownVector.push_back(TALC);
3642  }
3643  Utilities->CallLogPop(1979);
3644 }
3645 
3646 // ---------------------------------------------------------------------------
3647 
3648 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3649 /*
3650  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3651  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3652  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3653 */
3654 {
3655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3656  TTrackElement Next;
3657 
3658 // Disp->ClearDisplay();
3660  while(ReturnNextInactiveTrackElement(0, Next))
3661  {
3662  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3663  {
3664  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3665  {
3666  // only plot if on screen, to save time
3667  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3669  {
3670  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3671  }
3672  }
3673  }
3674  }
3675 
3676  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3677 
3678  NextTrackElementPtr = TrackVector.begin();
3679  while(ReturnNextTrackElement(0, Next))
3680  {
3681  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3682  {
3683  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3685  {
3686  if(Next.TrackType == Points)
3687  {
3688  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3689  }
3690  else if(Next.TrackType == SignalPost)
3691  {
3692  PlotSignal(9, Next, Disp);
3693  }
3694  else if(Next.TrackType == GapJump)
3695  {
3696  PlotGap(0, Next, Disp);
3697  }
3698  else
3699  {
3700  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3701  }
3702  }
3703  }
3704  }
3705 
3706  if(BothPointFilletsAndBasicLCs)
3707  {
3709  while(ReturnNextInactiveTrackElement(4, Next))
3710  {
3711  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3712  {
3713  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3714  {
3715  // only plot if on screen, to save time, & OK as plotting one by one here
3716  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3718  {
3719  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3720  {
3721  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3722  }
3723  else
3724  {
3725  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3726  }
3727  }
3728  }
3729  }
3730  }
3731  }
3732  Disp->Update();
3733  Utilities->CallLogPop(468);
3734 }
3735 
3736 // ---------------------------------------------------------------------------
3737 
3738 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3739 {
3740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3741  if(UserGraphicVector.empty())
3742  {
3743  Utilities->CallLogPop(2175);
3744  return;
3745  }
3746  TUserGraphicItem UGI;
3747 
3748  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3749  {
3750  UGI = UserGraphicVectorAt(4, x);
3751  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3752  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3753  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3754  {
3755  Disp->PlotAndAddUserGraphic(0, UGI);
3756  }
3757  }
3758  Disp->Update();
3759  Utilities->CallLogPop(2176);
3760 }
3761 
3762 // ---------------------------------------------------------------------------
3763 
3764 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3765 /*
3766  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3767 */
3768 {
3769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3770 // need to change graphics back to black on white if have a dark background
3771  TColor OldTransparentColour = Utilities->clTransparent;
3772 
3774  {
3775  Utilities->clTransparent = TColor(0xFFFFFF); // white
3778  }
3779  TTrackElement Next;
3780 
3781  Bitmap->Canvas->CopyMode = cmSrcCopy;
3783  Graphics::TBitmap *GraphicOutput;
3784 
3785  while(ReturnNextInactiveTrackElement(2, Next))
3786  {
3787  GraphicOutput = Next.GraphicPtr;
3788  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3789  {
3790  if(Next.LocationName == "") // plot as named or unnamed (striped)
3791  {
3792  // default is not striped
3793  switch(Next.SpeedTag)
3794  {
3795  case 76: // t platform
3796  GraphicOutput = RailGraphics->gl76Striped;
3797  break;
3798 
3799  case 77: // h platform
3800  GraphicOutput = RailGraphics->bm77Striped;
3801  break;
3802 
3803  case 78: // v platform
3804  GraphicOutput = RailGraphics->bm78Striped;
3805  break;
3806 
3807  case 79: // r platform
3808  GraphicOutput = RailGraphics->gl79Striped;
3809  break;
3810 
3811  case 96: // concourse
3812  GraphicOutput = RailGraphics->ConcourseStriped;
3813  break;
3814 
3815  case 129: // v footbridge
3816  GraphicOutput = RailGraphics->gl129Striped;
3817  break;
3818 
3819  case 130: // h footbridge
3820  GraphicOutput = RailGraphics->gl130Striped;
3821  break;
3822 
3823  case 131: // non-station named loc
3824  GraphicOutput = RailGraphics->bmNameStriped;
3825  break;
3826 
3827  case 145: // v underpass
3828  GraphicOutput = RailGraphics->gl145Striped;
3829  break;
3830 
3831  case 146: // h underpass
3832  GraphicOutput = RailGraphics->gl146Striped;
3833  break;
3834 
3835  default:
3836  GraphicOutput = Next.GraphicPtr;
3837  break;
3838  }
3839  }
3840  if(Next.SpeedTag == 144) // level crossing
3841  {
3842  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3843  {
3844  GraphicOutput = RailGraphics->LCBothVer;
3845  }
3846  else
3847  {
3848  GraphicOutput = RailGraphics->LCBothHor;
3849  }
3850  }
3851  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3852  }
3853  }
3854 
3855  NextTrackElementPtr = TrackVector.begin();
3856  while(ReturnNextTrackElement(2, Next))
3857  {
3858  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3859  {
3860  if(Next.TrackType == Points) // plot both fillets
3861  {
3862  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3863  if(Next.SpeedTag < 28)
3864  {
3865  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3867  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3869  }
3870  else if(Next.SpeedTag < 132)
3871  {
3872  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3873  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3874  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3875  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3876  }
3877  else
3878  {
3879  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3880  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3881  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3882  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3883  }
3884  }
3885  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3886  {
3887  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3888  {
3889  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3890  }
3891  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3892  {
3893  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3894  }
3895  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3896  {
3897  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3898  }
3899  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3900  {
3901  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3902  }
3903  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3904  {
3905  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3906  }
3907  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3908  {
3909  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3910  }
3911  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3912  {
3913  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3914  }
3915  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3916  {
3917  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3918  }
3919  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3920  {
3921  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3922  }
3923  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3924  {
3925  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3926  }
3927  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3928  {
3929  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3930  }
3931  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3932  {
3933  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3934  }
3935  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3936  {
3937  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3938  }
3939  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3940  {
3941  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3942  }
3943  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3944  {
3945  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3946  }
3947  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3948  {
3949  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3950  }
3951  }
3952  // below added for version 0.6, only stop signals to be drawn
3953  else if(Next.TrackType == SignalPost)
3954  {
3955  for(int x = 0; x < 40; x++)
3956  {
3957  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3958  {
3959  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3960  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3961  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3962  int HOffset = 0;
3963  if(Next.SpeedTag > 73)
3964  {
3965  HOffset = 5;
3966  }
3967  else if(Next.SpeedTag == 71)
3968  {
3969  HOffset = 9;
3970  }
3971  int VOffset = 0;
3972  if(Next.SpeedTag == 69)
3973  {
3974  VOffset = 9;
3975  }
3976  else if(Next.SpeedTag == 72)
3977  {
3978  VOffset = 5;
3979  }
3980  else if(Next.SpeedTag == 74)
3981  {
3982  VOffset = 5;
3983  }
3984  Graphics::TBitmap *GraphicPtr;
3985  if(Next.SpeedTag > 71)
3986  {
3987  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3988  }
3989  else if(Next.SpeedTag < 70)
3990  {
3991  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3992  }
3993  else
3994  {
3995  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3996  }
3997  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3998  // plot special signal platform if present
3999  Graphics::TBitmap* SignalPlatformGraphic;
4000  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4001  {
4002  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4003  }
4004  // now plot signal (double yellow overwrites most of signal platform if present)
4005  // below amended for version 0.6
4007  {
4008  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4009  }
4010  else if(Next.SigAspect == TTrackElement::TwoAspect)
4011  {
4012  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4013  }
4014  else if(Next.SigAspect == TTrackElement::GroundSignal)
4015  {
4016  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4017  }
4018  else // 4 aspect
4019  {
4020  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4021  }
4022  break;
4023  }
4024  }
4025  }
4026  else
4027  {
4028  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4029  }
4030  }
4031  }
4032  if(OldTransparentColour != clB5G5R5)
4033  {
4034  Utilities->clTransparent = OldTransparentColour; // restore
4037  }
4038  Utilities->CallLogPop(1533);
4039 }
4040 
4041 // ---------------------------------------------------------------------------
4042 
4043 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4044 {
4045  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4046  if(UserGraphicVector.empty())
4047  {
4048  Utilities->CallLogPop(2192);
4049  return;
4050  }
4051  else
4052  {
4053  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4054  {
4055  Bitmap->Canvas->CopyMode = cmSrcCopy;
4056  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4057  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4058  }
4059  }
4060  Utilities->CallLogPop(2193);
4061 }
4062 
4063 // ---------------------------------------------------------------------------
4064 
4065 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
4066 /*
4067  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4068  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4069 */
4070 {
4071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
4072 // need to change graphics back to black on white if have a dark background
4073  TColor OldTransparentColour = Utilities->clTransparent;
4074 
4076  {
4077  Utilities->clTransparent = TColor(0xFFFFFF); // white
4080  }
4081  TTrackElement Next;
4082 
4083  Bitmap->Canvas->CopyMode = cmSrcCopy;
4085  Graphics::TBitmap *GraphicOutput;
4086 
4087  while(ReturnNextInactiveTrackElement(3, Next))
4088  {
4089  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4090  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4091  {
4092  if(Next.SpeedTag == 144) // level crossing
4093  {
4094  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4095  if(BaseElement == 1) // hor element
4096  {
4097  if(Next.Attribute == 1) // open to trains
4098  {
4099  GraphicOutput = RailGraphics->LCBothHor;
4100  }
4101  else // plot as closed to trains if in any other state
4102  {
4103  GraphicOutput = RailGraphics->LCBothVer;
4104  }
4105  }
4106  else // vert element
4107  {
4108  if(Next.Attribute == 1) // open to trains
4109  {
4110  GraphicOutput = RailGraphics->LCBothVer;
4111  }
4112  else // plot as closed to trains if in any other state
4113  {
4114  GraphicOutput = RailGraphics->LCBothHor;
4115  }
4116  }
4117  }
4118  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4119  }
4120  }
4121 
4122  NextTrackElementPtr = TrackVector.begin();
4123  while(ReturnNextTrackElement(3, Next))
4124  {
4125  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4126  {
4127  if(Next.TrackType == Points) // plot active fillet
4128  {
4129  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4130  if(Next.SpeedTag < 28)
4131  {
4132  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4134  }
4135  else if(Next.SpeedTag < 132)
4136  {
4137  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4139  }
4140  else
4141  {
4142  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4144  }
4145  }
4146  else if(Next.TrackType == GapJump) // plot as connected
4147  {
4148  if(Next.SpeedTag == 88)
4149  {
4150  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4151  }
4152  else if(Next.SpeedTag == 89)
4153  {
4154  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4155  }
4156  else if(Next.SpeedTag == 90)
4157  {
4158  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4159  }
4160  else if(Next.SpeedTag == 91)
4161  {
4162  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4163  }
4164  else if(Next.SpeedTag == 92)
4165  {
4166  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4167  }
4168  else if(Next.SpeedTag == 93)
4169  {
4170  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4171  }
4172  else if(Next.SpeedTag == 94)
4173  {
4174  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4175  }
4176  else if(Next.SpeedTag == 95)
4177  {
4178  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4179  }
4180  }
4181  else if(Next.TrackType == SignalPost) // plot in correct colour
4182  {
4183  for(int x = 0; x < 40; x++)
4184  {
4185  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4186  {
4187  // plot blank first, then plot platform if present - (always not striped for operating railway)
4188  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4189  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4190  int HOffset = 0;
4191  if(Next.SpeedTag > 73)
4192  {
4193  HOffset = 5;
4194  }
4195  else if(Next.SpeedTag == 71)
4196  {
4197  HOffset = 9;
4198  }
4199  int VOffset = 0;
4200  if(Next.SpeedTag == 69)
4201  {
4202  VOffset = 9;
4203  }
4204  else if(Next.SpeedTag == 72)
4205  {
4206  VOffset = 5;
4207  }
4208  else if(Next.SpeedTag == 74)
4209  {
4210  VOffset = 5;
4211  }
4212  Graphics::TBitmap *GraphicPtr;
4213  if(Next.SpeedTag > 71)
4214  {
4215  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4216  }
4217  else if(Next.SpeedTag < 70)
4218  {
4219  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4220  }
4221  else
4222  {
4223  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4224  }
4225  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4226  // plot special signal platform if present
4227  Graphics::TBitmap* SignalPlatformGraphic;
4228  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4229  {
4230  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4231  }
4232  // now plot signal (double yellow overwrites most of signal platform if present)
4233  // below amended for version 0.6
4235  {
4236  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4237  }
4238  else if(Next.SigAspect == TTrackElement::TwoAspect)
4239  {
4240  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4241  }
4242  else if(Next.SigAspect == TTrackElement::GroundSignal)
4243  {
4244  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4245  }
4246  else // 4 aspect
4247  {
4248  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4249  }
4250  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4251  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4252  {
4253  if(Next.SpeedTag == 68)
4254  {
4255  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4256  }
4257  if(Next.SpeedTag == 69)
4258  {
4259  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4260  }
4261  if(Next.SpeedTag == 70)
4262  {
4263  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4264  }
4265  if(Next.SpeedTag == 71)
4266  {
4267  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4268  }
4269  if(Next.SpeedTag == 72)
4270  {
4271  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4272  }
4273  if(Next.SpeedTag == 73)
4274  {
4275  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4276  }
4277  if(Next.SpeedTag == 74)
4278  {
4279  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4280  }
4281  if(Next.SpeedTag == 75)
4282  {
4283  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4284  }
4285  }
4286  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4287  {
4288  for(int x = 0; x < 40; x++)
4289  {
4290  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4291  {
4292  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4293  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4294  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4295  // plot special signal platform if present
4296  Graphics::TBitmap* SignalPlatformGraphic;
4297  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4298  {
4299  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4300  }
4301  // now plot signal
4302  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4303  break;
4304  }
4305  }
4306  }
4307  break;
4308  }
4309  }
4310  }
4311  else
4312  {
4313  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4314  }
4315  }
4316  }
4317  if(OldTransparentColour != clB5G5R5)
4318  {
4319  Utilities->clTransparent = OldTransparentColour; // restore
4322  }
4323  Utilities->CallLogPop(1701);
4324 }
4325 
4326 // ---------------------------------------------------------------------------
4327 
4328 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4329 {
4330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4331  for(unsigned int x = 0; x < TrackVector.size(); x++)
4332  {
4333  if(TrackVector.at(x).TrackType == GapJump)
4334  {
4335  if(TrackVector.at(x).Conn[0] > -1)
4336  {
4337  continue; // to next 'x' value as this element has already been set
4338  }
4339  // here if identify a GapJump element not yet set
4340  GapPos = x;
4341  GapHLoc = TrackVector.at(x).HLoc;
4342  GapVLoc = TrackVector.at(x).VLoc;
4343  // highlight it
4345  Utilities->CallLogPop(469);
4346  return(true);
4347  }
4348  }
4349  Utilities->CallLogPop(470);
4350  return(false);
4351 }
4352 
4353 // ---------------------------------------------------------------------------
4354 
4355 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4356 {
4357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4358  AnsiString(VLoc));
4359  int Position;
4360  TTrackElement TrackElement;
4361 
4362  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4363  {
4364  Utilities->CallLogPop(471);
4365  return(false); // not found
4366  }
4367  if(TrackElement.TrackType != GapJump)
4368  {
4369  Utilities->CallLogPop(472);
4370  return(false); // found something but not a gap
4371  }
4372  if(Position == GapPos)
4373  {
4374  Utilities->CallLogPop(473);
4375  return(false); // selected original gap
4376  }
4377  if(TrackVector.at(Position).Conn[0] != -1)
4378  {
4379  Utilities->CallLogPop(474);
4380  return(false); // already selected
4381  }
4382  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4383  TrackVector.at(Position).ConnLinkPos[0] = 0;
4384  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4385  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4386 // now highlight the selected location
4387  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4388  Utilities->CallLogPop(475);
4389  return(true);
4390 }
4391 
4392 // ---------------------------------------------------------------------------
4393 
4394 bool TTrack::GapsUnset(int Caller)
4395 // returns true if there are gaps and any are unset
4396 {
4397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4398  if(TrackVector.size() == 0)
4399  {
4400  Utilities->CallLogPop(476);
4401  return(false);
4402  }
4403  for(unsigned int x = 0; x < TrackVector.size(); x++)
4404  {
4405  if(TrackVector.at(x).TrackType == GapJump)
4406  {
4407  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4408  {
4409  Utilities->CallLogPop(477);
4410  return(true);
4411  }
4412  else // set, but may not have matching element, or that element may not be set
4413  {
4414  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4415  // check that the element pointed to by the gap link is a GapJump
4416  {
4417  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4418  Utilities->CallLogPop(1137);
4419  return(false);
4420  }
4421 // here if gap connection is itself a GapJump
4422  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4423  // check that the element pointed to by the gap link is a GapJump & that its gap link
4424  // points back to 'x'
4425  {
4426  Utilities->CallLogPop(478);
4427  return(true);
4428  }
4429 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4430  }
4431  } // if(TrackVector.at(x).TrackType == GapJump)
4432 
4433  } // for x...
4434  Utilities->CallLogPop(479);
4435  return(false);
4436 }
4437 
4438 // ---------------------------------------------------------------------------
4439 
4440 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4441 {
4442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4443  for(unsigned int x = 0; x < TrackVector.size(); x++)
4444  {
4445  if(TrackVector.at(x).TrackType == GapJump)
4446  {
4447  Utilities->CallLogPop(1105);
4448  return(false);
4449  }
4450  }
4451  Utilities->CallLogPop(1106);
4452  return(true);
4453 }
4454 
4455 // ---------------------------------------------------------------------------
4456 
4457 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4458 {
4459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4460  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4461  {
4462  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4463  {
4464  Utilities->CallLogPop(1107);
4465  return(false);
4466  }
4467  }
4468  for(unsigned int x = 0; x < TrackVector.size(); x++)
4469  {
4470  if(TrackVector.at(x).FixedNamedLocationElement)
4471  {
4472  Utilities->CallLogPop(1108);
4473  return(false);
4474  }
4475  }
4476  Utilities->CallLogPop(1109);
4477  return(true);
4478 }
4479 
4480 // ---------------------------------------------------------------------------
4481 
4483 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4484 // returns false otherwise or if there are no NamedLocationElements
4485 {
4486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4487  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4488  {
4489  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4490  {
4491  if(InactiveTrackVector.at(x).LocationName == "")
4492  {
4493  Utilities->CallLogPop(1110);
4494  return(true);
4495  }
4496  }
4497  }
4498  for(unsigned int x = 0; x < TrackVector.size(); x++)
4499  {
4500  if(TrackVector.at(x).FixedNamedLocationElement)
4501  {
4502  if(TrackVector.at(x).LocationName == "")
4503  {
4504  Utilities->CallLogPop(1111);
4505  return(true);
4506  }
4507  }
4508  }
4509  Utilities->CallLogPop(1112);
4510  return(false);
4511 }
4512 
4513 // ---------------------------------------------------------------------------
4514 
4515 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4516 {
4517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4518  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4519  Utilities->CallLogPop(480);
4520 }
4521 
4522 // ---------------------------------------------------------------------------
4523 
4525 {
4526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4527  if(TrackVector.size() == 0)
4528  {
4529  Utilities->CallLogPop(481);
4530  return;
4531  }
4532  for(unsigned int x = 0; x < TrackVector.size(); x++)
4533  {
4534  if(TrackVector.at(x).TrackType == GapJump)
4535  {
4536  if(TrackVector.at(x).Conn[0] > -1) // set
4537  {
4538  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4539  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4540  {
4541  TrackVector.at(x).Conn[0] = -1;
4542  TrackVector.at(x).ConnLinkPos[0] = -1;
4543  continue; // to next 'x'
4544  }
4545 // here if gap connection is itself a GapJump
4546  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4547  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4548  // if not clear Conns & CLks
4549  {
4550  TrackVector.at(x).Conn[0] = -1;
4551  TrackVector.at(x).ConnLinkPos[0] = -1;
4552  continue; // to next 'x'
4553  }
4554 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4555 // hence no more action needed on these Conns & CLks
4556  }
4557  } // else //gap jump
4558 
4559  } // for x...
4560 // throw Exception("Test Exception");//test
4561  Utilities->CallLogPop(482);
4562 }
4563 
4564 // ---------------------------------------------------------------------------
4565 
4566 void TTrack::ResetSignals(int Caller)
4567 {
4568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4569  for(unsigned int x = 0; x < TrackVector.size(); x++)
4570  {
4571  if(TrackVector.at(x).TrackType == SignalPost)
4572  {
4573  TrackVector.at(x).Attribute = 0;
4574  }
4575  }
4576  Utilities->CallLogPop(483);
4577 }
4578 
4579 // ---------------------------------------------------------------------------
4580 
4581 void TTrack::ResetPoints(int Caller)
4582 {
4583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4584  for(unsigned int x = 0; x < TrackVector.size(); x++)
4585  {
4586  if(TrackVector.at(x).TrackType == Points)
4587  {
4588  TrackVector.at(x).Attribute = 0;
4589  }
4590  }
4591  Utilities->CallLogPop(484);
4592 }
4593 
4594 // ---------------------------------------------------------------------------
4595 
4596 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4597 {
4598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4599  if(TrackVector.empty())
4600  {
4601  TrackMap.clear();
4602  Utilities->CallLogPop(485);
4603  return(true);
4604  }
4605 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4606  THVPair TrackMapKeyPair;
4607 
4608  NewVector.clear();
4609  TTrackMapIterator TrackMapPtr;
4610 
4611  if(!TrackMap.empty())
4612  {
4613  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4614  {
4615  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4616  }
4617  }
4618  if(NewVector.size() != TrackMap.size())
4619  {
4620  throw Exception("Error - Map & Vector different sizes");
4621  }
4622  unsigned int NonZeroCount = 0;
4623 
4624  for(unsigned int x = 0; x < TrackVector.size(); x++)
4625  {
4626  if(TrackVector.at(x).TrackType != Erase)
4627  {
4628  NonZeroCount++;
4629  }
4630  }
4631  if(NewVector.size() != NonZeroCount)
4632  {
4633  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4634  }
4636  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4637  TTrackMapEntry TrackMapEntry;
4638 
4639  for(unsigned int x = 0; x < TrackVector.size(); x++)
4640  {
4641  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4642  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4643  TrackMapEntry.first = TrackMapKeyPair;
4644  TrackMapEntry.second = x;
4645  if(!(TrackMap.insert(TrackMapEntry).second))
4646  {
4647  throw Exception("Error - map insertion failure, TrackVector in error");
4648  }
4649  }
4650 // All track now relocated in TrackVector, reset all Conns & CLks
4651  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4652  {
4653  for(unsigned int y = 0; y < 4; y++)
4654  {
4655  TrackVector.at(x).Conn[y] = -1;
4656  TrackVector.at(x).ConnLinkPos[y] = -1;
4657  }
4658  }
4659  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4660  CheckMapAndTrack(4); // test
4661  CheckMapAndInactiveTrack(4); // test
4662  CheckLocationNameMultiMap(8); // test
4663  if(!ResetGapsFromGapMap(1))
4664  {
4665  Utilities->CallLogPop(489);
4666  return(false);
4667  }
4668  Utilities->CallLogPop(490);
4669  return(true);
4670 }
4671 
4672 // ---------------------------------------------------------------------------
4673 
4674 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4675 {
4676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4677  GapMap.clear();
4678  THVPair GapMapKeyPair, GapMapValuePair;
4679  TGapMapEntry GapMapEntry;
4680 
4681  for(unsigned int x = 0; x < TrackVector.size(); x++)
4682  {
4683  if(TrackVector.at(x).TrackType == GapJump)
4684  {
4685  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4686  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4687  GapMapEntry.first = GapMapKeyPair;
4688  if(TrackVector.at(x).Conn[0] == -1)
4689  {
4690  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4691  }
4692  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4693  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4694  GapMapEntry.second = GapMapValuePair;
4695  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4696  {
4697  GapMap.insert(GapMapEntry);
4698  }
4699  }
4700  }
4701  Utilities->CallLogPop(492);
4702 }
4703 
4704 // ---------------------------------------------------------------------------
4705 
4706 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4707 {
4708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4709  LocError = false;
4710  bool CheckForLinks = false;
4711 
4712  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4713  {
4714  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4715  {
4716  continue; // skip blank elements
4717  }
4718 // check footcrossing linkages
4719  if(TrackVector.at(x).TrackType == FootCrossing)
4720  {
4721  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4722  {
4723  ShowMessage(
4724  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4725  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4726  "can't connect to an underpass or vice versa)");
4727  HLoc = TrackVector.at(x).HLoc;
4728  VLoc = TrackVector.at(x).VLoc;
4729  LocError = true;
4730  Utilities->CallLogPop(493);
4731  return(false);
4732  }
4733  }
4734  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4735  {
4736  CheckForLinks = false;
4737  if(TrackVector.at(x).Link[y] <= 0)
4738  {
4739  continue; // no link
4740  }
4741  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4742  {
4743  continue; // buffer
4744  }
4745  if(TrackVector.at(x).Config[y] == Gap)
4746  {
4747  continue; // gaps set later from GapMap
4748 
4749  }
4750  // get required H & V for track element joining link 'y'
4751  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4752  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4753  // find track element if present
4754  bool ConnectionFoundFlag;
4755  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4756  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4757  {
4758  ShowMessage("Can't have a track element adjacent to a continuation exit");
4759  HLoc = TrackVector.at(x).HLoc;
4760  VLoc = TrackVector.at(x).VLoc;
4761  LocError = true;
4762  if(FinalCall)
4763  {
4764  throw Exception("Error in final track linkage - continuation adjacent to another element");
4765  }
4766  Utilities->CallLogPop(1539);
4767  return(false);
4768  }
4769  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4770  {
4771  continue;
4772  }
4773  if(ConnectionFoundFlag)
4774  {
4775  TrackVector.at(x).Conn[y] = VecPos;
4776  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4777  bool LinkFoundFlag = false;
4778  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4779  {
4780  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4781  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4782  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4783  }
4784  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4785  && (TrackVector.at(VecPos).TrackType == Buffers))
4786  {
4787  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4788  // need room for a train (2 elements) without fouling points or signals
4789  }
4790  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4791  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4792  {
4793  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4794  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4795  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4796  // be named but needs the adjacent element named too
4797  }
4798  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4799  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4800  {
4801  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4802  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4803  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4804  }
4805  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4806  {
4807  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4808  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4809  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4810  }
4811  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4812  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4813  {
4814  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4815  }
4816  else
4817  {
4818  CheckForLinks = true;
4819  }
4820  if(CheckForLinks)
4821  {
4822  for(unsigned int a = 0; a < 4; a++)
4823  {
4824  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4825  (TrackVector.at(VecPos).Config[a] != Gap))
4826  {
4827  TrackVector.at(x).ConnLinkPos[y] = a;
4828  // note - this ensures that if the connecting element is a leading point
4829  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4830  // (Points have the same link value for both [0] and [2])
4831  LinkFoundFlag = true;
4832  break; // stop after first find or will find later link for leading point
4833  }
4834  }
4835  }
4836  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4837  if(!LinkFoundFlag)
4838  {
4839  HLoc = TrackVector.at(x).HLoc;
4840  VLoc = TrackVector.at(x).VLoc;
4841  LocError = true;
4842  if(FinalCall)
4843  {
4844  throw Exception("Error in final track linkage - invalid link");
4845  }
4846  Utilities->CallLogPop(494);
4847  return(false);
4848  }
4849  }
4850  // if there isn't a connection set the invert values for the offending element
4851  else // if(ConnectionFoundFlag)
4852  {
4853  HLoc = TrackVector.at(x).HLoc;
4854  VLoc = TrackVector.at(x).VLoc;
4855  LocError = true;
4856  if(FinalCall)
4857  {
4858  throw Exception("Error in final track linkage - connection not found");
4859  }
4860  Utilities->CallLogPop(495);
4861  return(false);
4862  }
4863  }
4864  } // for(unsigned int x=0;x<TrackVector.size();x++)
4865 
4866  if(FinalCall)
4867  {
4869  }
4870 // final check
4871  bool ConnErrorFlag = false;
4872 
4873  for(unsigned int x = 0; x < TrackVector.size(); x++)
4874  {
4875  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4876  {
4877  ConnErrorFlag = true;
4878  }
4879  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4880  {
4881  ConnErrorFlag = true;
4882  }
4883  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4884  {
4885  ConnErrorFlag = true;
4886  }
4887  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4888  {
4889  ConnErrorFlag = true;
4890  }
4891  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4892  {
4893  if(TrackVector.at(x).ActiveTrackElementName == "")
4894  {
4895  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4896  {
4897  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4898  }
4899  }
4900  }
4901  }
4902  if(ConnErrorFlag)
4903  {
4904  if(FinalCall)
4905  {
4906  throw Exception("ConnError in LinkTrack - Final");
4907  }
4908  else
4909  {
4910  throw Exception("ConnError in LinkTrack - Precheck");
4911  }
4912  }
4913  bool CLkErrorFlag = false;
4914 
4915  for(unsigned int x = 0; x < TrackVector.size(); x++)
4916  {
4917  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4918  {
4919  CLkErrorFlag = true;
4920  }
4921  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4922  {
4923  CLkErrorFlag = true;
4924  }
4925  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4926  {
4927  CLkErrorFlag = true;
4928  }
4929  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4930  {
4931  CLkErrorFlag = true;
4932  }
4933  }
4934 
4935  if(CLkErrorFlag)
4936  {
4937  if(FinalCall)
4938  {
4939  throw Exception("CLkError in LinkTrack - Final");
4940  }
4941  else
4942  {
4943  throw Exception("CLkError in LinkTrack - Precheck");
4944  }
4945  }
4946 // set element lengths to min of 20m
4947  for(unsigned int x = 0; x < TrackVector.size(); x++)
4948  {
4949  if(TrackVector.at(x).TrackType == Erase)
4950  {
4951  continue; // skip blank elements
4952  }
4953  if(TrackVector.at(x).Length01 < 20)
4954  {
4955  TrackVector.at(x).Length01 = 20;
4956  }
4957  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4958  {
4959  TrackVector.at(x).Length23 = 20;
4960  }
4961  }
4962 
4963  if(FinalCall) // ONLY at FinalCall, no point calling twice
4964  {
4965  CalcHLocMinEtc(3);
4966  }
4967 
4968  Utilities->CallLogPop(497);
4969  return(true);
4970 }
4971 
4972 // ---------------------------------------------------------------------------
4973 
4974 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4975 {
4976  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4977  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4978  {
4979  if(TrackVector.at(x).TrackType == Erase)
4980  {
4981  continue; // skip blank elements
4982 
4983  }
4984 // check footcrossing linkages
4985  if(TrackVector.at(x).TrackType == FootCrossing)
4986  {
4987  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4988  {
4989  Utilities->CallLogPop(1127);
4990  return(false);
4991  }
4992  }
4993  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4994  {
4995  if(TrackVector.at(x).Link[y] <= 0)
4996  {
4997  continue; // no link
4998  }
4999  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
5000  {
5001  continue; // buffer
5002  }
5003  if(TrackVector.at(x).Config[y] == Gap)
5004  {
5005  continue; // gaps set later from GapMap
5006 
5007  }
5008  // get required H & V for track element joining link 'y'
5009  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
5010  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
5011  // find track element if present
5012  bool ConnectionFoundFlag;
5013  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5014  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5015  {
5016  if(FinalCall)
5017  {
5018  throw Exception("Error in final track linkage - continuation adjacent to another element");
5019  }
5020  Utilities->CallLogPop(1540);
5021  return(false);
5022  }
5023  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
5024  {
5025  continue;
5026  }
5027  if(ConnectionFoundFlag)
5028  {
5029  TrackVector.at(x).Conn[y] = VecPos;
5030  bool LinkFoundFlag = false;
5031  // find connecting link in the newly found track element if there is one & make checks
5032  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
5033  (TrackVector.at(VecPos).TrackType == Buffers))
5034  {
5035  Utilities->CallLogPop(1541);
5036  return(false);
5037  }
5038  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
5039  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
5040  {
5041  Utilities->CallLogPop(1542);
5042  return(false);
5043  }
5044  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
5045  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
5046  {
5047  Utilities->CallLogPop(1543);
5048  return(false);
5049  }
5050  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
5051  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5052  {
5053  Utilities->CallLogPop(1981);
5054  return(false);
5055  }
5056 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5057  else if(TrackVector.at(x).TrackType == Continuation)
5058  {
5059  int H = TrackVector.at(x).HLoc;
5060  int V = TrackVector.at(x).VLoc;
5061  bool FoundFlag = false;
5062  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5063  if(FoundFlag)
5064  {
5065  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5066  {
5067  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
5068  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
5069  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5070  if(FoundFlag)
5071  {
5072  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5073  {
5074  Utilities->CallLogPop(1544);
5075  return false;
5076  }
5077  }
5078  else
5079  {
5080  Utilities->CallLogPop(1545);
5081  return false;
5082  }
5083  }
5084  }
5085  }
5086 */
5087  for(unsigned int a = 0; a < 4; a++)
5088  {
5089  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
5090  (TrackVector.at(VecPos).Config[a] != Gap))
5091  {
5092  TrackVector.at(x).ConnLinkPos[y] = a;
5093  // note - this ensures that if the connecting element is a leading point
5094  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5095  // (Points have the same link value for both [0] and [2])
5096  LinkFoundFlag = true;
5097  break; // stop after first find or will find later link for leading point
5098  }
5099  }
5100  if(!LinkFoundFlag)
5101  {
5102  if(FinalCall)
5103  {
5104  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5105  }
5106  Utilities->CallLogPop(1128);
5107  return(false);
5108  }
5109  }
5110  else // if(ConnectionFoundFlag)
5111  {
5112  if(FinalCall)
5113  {
5114  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5115  }
5116  Utilities->CallLogPop(1129);
5117  return(false);
5118  }
5119  }
5120  } // for(unsigned int x=0;x<TrackVector.size();x++)
5121 
5122  if(FinalCall)
5123  {
5125  }
5126 // final check
5127  bool ConnErrorFlag = false;
5128 
5129  for(unsigned int x = 0; x < TrackVector.size(); x++)
5130  {
5131  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
5132  {
5133  ConnErrorFlag = true;
5134  }
5135  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
5136  {
5137  ConnErrorFlag = true;
5138  }
5139  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
5140  {
5141  ConnErrorFlag = true;
5142  }
5143  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
5144  {
5145  ConnErrorFlag = true;
5146  }
5147  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5148  {
5149  if(TrackVector.at(x).ActiveTrackElementName == "")
5150  {
5151  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
5152  {
5153  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5154  }
5155  }
5156  }
5157  }
5158  if(ConnErrorFlag)
5159  {
5160  if(FinalCall)
5161  {
5162  throw Exception("ConnError in LinkTrack - Final");
5163  }
5164  else
5165  {
5166  throw Exception("ConnError in LinkTrack - Precheck");
5167  }
5168  }
5169  bool CLkErrorFlag = false;
5170 
5171  for(unsigned int x = 0; x < TrackVector.size(); x++)
5172  {
5173  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
5174  {
5175  CLkErrorFlag = true;
5176  }
5177  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
5178  {
5179  CLkErrorFlag = true;
5180  }
5181  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
5182  {
5183  CLkErrorFlag = true;
5184  }
5185  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
5186  {
5187  CLkErrorFlag = true;
5188  }
5189  }
5190 
5191  if(CLkErrorFlag)
5192  {
5193  if(FinalCall)
5194  {
5195  throw Exception("CLkError in LinkTrack - Final");
5196  }
5197  else
5198  {
5199  throw Exception("CLkError in LinkTrack - Precheck");
5200  }
5201  }
5202 // set element lengths to min of 20m
5203  for(unsigned int x = 0; x < TrackVector.size(); x++)
5204  {
5205  if(TrackVector.at(x).TrackType == Erase)
5206  {
5207  continue; // skip blank elements
5208  }
5209  if(TrackVector.at(x).Length01 < 20)
5210  {
5211  TrackVector.at(x).Length01 = 20;
5212  }
5213  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
5214  {
5215  TrackVector.at(x).Length23 = 20;
5216  }
5217  }
5218 
5219  if(FinalCall) // ONLY at FinalCall, no point calling twice
5220  {
5221  CalcHLocMinEtc(7);
5222  }
5223  Utilities->CallLogPop(1130);
5224  return(true);
5225 }
5226 
5227 // ---------------------------------------------------------------------------
5228 
5229 bool TTrack::IsTrackLinked(int Caller) // not used any more
5230 {
5231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5232  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5233  {
5234  if(TrackVector.at(x).TrackType == Erase)
5235  {
5236  Utilities->CallLogPop(498);
5237  return(false);
5238  }
5239 // check foot linkages
5240  if(TrackVector.at(x).TrackType == FootCrossing)
5241  {
5242  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
5243  {
5244  Utilities->CallLogPop(499);
5245  return(false);
5246  }
5247  }
5248  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5249  {
5250  if(TrackVector.at(x).Link[y] <= 0)
5251  {
5252  continue; // no link
5253  }
5254  if(TrackVector.at(x).Config[y] == End)
5255  {
5256  continue; // buffer or continuation
5257  }
5258  if(TrackVector.at(x).Config[y] == Gap)
5259  {
5260  continue; // gaps set later from GapMap
5261 
5262  }
5263  // get required H & V for track element joining link 'y'
5264  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
5265  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
5266  // find track element if present
5267  bool ConnectionFoundFlag = false;
5268  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5269  if(ConnectionFoundFlag)
5270  {
5271  TrackVector.at(x).Conn[y] = VecPos;
5272  // find connecting link in the newly found track element if there is one & make buffer check
5273  bool LinkFoundFlag = false;
5274  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
5275  (TrackVector.at(VecPos).TrackType == Buffers))
5276  {
5277  Utilities->CallLogPop(500);
5278  return(false);
5279  }
5280  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
5281  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
5282  {
5283  Utilities->CallLogPop(501);
5284  return(false);
5285  }
5286  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
5287  {
5288  Utilities->CallLogPop(502);
5289  return(false);
5290  }
5291  else
5292  {
5293  for(unsigned int a = 0; a < 4; a++)
5294  {
5295  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
5296  (TrackVector.at(VecPos).Config[a] != Gap))
5297  {
5298  TrackVector.at(x).ConnLinkPos[y] = a;
5299  // note - this ensures that if the connecting element is a leading point
5300  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5301  // (Points have the same link value for both [0] and [2])
5302  LinkFoundFlag = true;
5303  break; // stop after first find or will find later link for leading point
5304  }
5305  }
5306  }
5307  if(!LinkFoundFlag)
5308  {
5309  Utilities->CallLogPop(503);
5310  return(false);
5311  }
5312  }
5313  else // if(ConnectionFoundFlag)
5314  {
5315  Utilities->CallLogPop(504);
5316  return(false);
5317  }
5318  }
5319  } // for(unsigned int x=0;x<TrackVector.size();x++)
5320 
5321 // final check
5322  bool ConnErrorFlag = false;
5323 
5324  for(unsigned int x = 0; x < TrackVector.size(); x++)
5325  {
5326  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
5327  {
5328  ConnErrorFlag = true;
5329  }
5330  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
5331  {
5332  ConnErrorFlag = true;
5333  }
5334  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
5335  {
5336  ConnErrorFlag = true;
5337  }
5338  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
5339  {
5340  ConnErrorFlag = true;
5341  }
5342  }
5343  if(ConnErrorFlag)
5344  {
5345  Utilities->CallLogPop(505);
5346  return(false);
5347  }
5348  bool CLkErrorFlag = false;
5349 
5350  for(unsigned int x = 0; x < TrackVector.size(); x++)
5351  {
5352  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
5353  {
5354  CLkErrorFlag = true;
5355  }
5356  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
5357  {
5358  CLkErrorFlag = true;
5359  }
5360  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
5361  {
5362  CLkErrorFlag = true;
5363  }
5364  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
5365  {
5366  CLkErrorFlag = true;
5367  }
5368  }
5369 
5370  if(CLkErrorFlag)
5371  {
5372  Utilities->CallLogPop(506);
5373  return(false);
5374  }
5375  Utilities->CallLogPop(507);
5376  return(true);
5377 }
5378 
5379 // ---------------------------------------------------------------------------
5380 
5382 {
5383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5384  int Position1, Position2;
5385  TTrackElement TrackElement1, TrackElement2;
5386  TGapMapIterator GapMapPtr;
5387 
5388  if(!GapMap.empty())
5389  {
5390  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5391  {
5392  int HLoc1 = GapMapPtr->first.first;
5393  int VLoc1 = GapMapPtr->first.second;
5394  int HLoc2 = GapMapPtr->second.first;
5395  int VLoc2 = GapMapPtr->second.second;
5396  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5397  {
5398  throw Exception("Failed to find H & V for gap1, GapMap in error");
5399  }
5400  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5401  {
5402  throw Exception("Failed to find H & V for gap2, GapMap in error");
5403  }
5404  if(TrackElementAt(9, Position1).TrackType != GapJump)
5405  {
5406  throw Exception("Element at Pos1 not a gap, GapMap in error");
5407  }
5408  if(TrackElementAt(10, Position2).TrackType != GapJump)
5409  {
5410  throw Exception("Element at Pos2 not a gap, GapMap in error");
5411  }
5412  TrackElementAt(11, Position1).Conn[0] = Position2;
5413  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5414  TrackElementAt(13, Position2).Conn[0] = Position1;
5415  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5416  }
5417  }
5418  Utilities->CallLogPop(510);
5419  return(true);
5420 }
5421 
5422 // ---------------------------------------------------------------------------
5423 
5424 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5425 {
5426 // TIMPair MapEntry;
5427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5428  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5429  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5430  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5431  TLocationNameMultiMapEntry LocationNameEntry;
5432 
5433  LocationNameEntry.first = TrackElement.LocationName;
5434  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5435  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5436  {
5437 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5438 // could arise when loading old railways with multiple NonStationNamedLocs
5439  bool FoundFlag = false;
5440  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5441  if(FoundFlag)
5442  {
5443  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5444  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5445  {
5446  Utilities->CallLogPop(1813);
5447  return;
5448  }
5449  }
5450  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5451  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5452  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5453  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5454  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5455  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5456  if(TrackElement.FixedNamedLocationElement)
5457  {
5458  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5459  LocationNameMultiMap.insert(LocationNameEntry);
5460  }
5461  if(TrackElement.HLoc < HLocMin)
5462  {
5463  HLocMin = TrackElement.HLoc;
5464  }
5465  if(TrackElement.HLoc > HLocMax)
5466  {
5467  HLocMax = TrackElement.HLoc;
5468  }
5469  if(TrackElement.VLoc < VLocMin)
5470  {
5471  VLocMin = TrackElement.VLoc;
5472  }
5473  if(TrackElement.VLoc > VLocMax)
5474  {
5475  VLocMax = TrackElement.VLoc;
5476  }
5477  }
5478  else
5479  {
5480 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5481 // shouldn't arise but leave in as a safeguard
5482  bool FoundFlag = false;
5483  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5484  if(FoundFlag)
5485  {
5486  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5487  {
5488  Utilities->CallLogPop(1814);
5489  return;
5490  }
5491  }
5492  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5493  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5494  {
5495  TrackMapKeyPair.first = TrackElement.HLoc;
5496  TrackMapKeyPair.second = TrackElement.VLoc;
5497  TrackMapEntry.first = TrackMapKeyPair;
5498  TrackMapEntry.second = TrackVector.size() - 1;
5499  TrackMap.insert(TrackMapEntry);
5500  if(TrackElement.FixedNamedLocationElement)
5501  {
5502  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5503  LocationNameMultiMap.insert(LocationNameEntry);
5504  }
5505  if(TrackElement.HLoc < HLocMin)
5506  {
5507  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5508  }
5509  if(TrackElement.HLoc > HLocMax)
5510  {
5511  HLocMax = TrackElement.HLoc;
5512  }
5513  if(TrackElement.VLoc < VLocMin)
5514  {
5515  VLocMin = TrackElement.VLoc;
5516  }
5517  if(TrackElement.VLoc > VLocMax)
5518  {
5519  VLocMax = TrackElement.VLoc;
5520  }
5521  }
5522  }
5523 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5524 // CheckMapAndInactiveTrack(6);//test
5525 
5526 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5527 // with the Platforms until layout fully loaded
5528  Utilities->CallLogPop(511);
5529 }
5530 
5531 // ---------------------------------------------------------------------------
5532 
5533 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5534 {
5535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5536  AnsiString(VLoc));
5537  THVPair TrackMapKeyPair;
5538 
5539  FoundFlag = false;
5540  TTrackMapIterator TrackMapPtr;
5541 
5542  TrackMapKeyPair.first = HLoc;
5543  TrackMapKeyPair.second = VLoc;
5544  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5545  if(TrackMapPtr == TrackMap.end())
5546  {
5547  Utilities->CallLogPop(512);
5548  return(-1); // nothing found
5549  }
5550  else
5551  {
5552  FoundFlag = true;
5553  Utilities->CallLogPop(513);
5554  return(TrackMapPtr->second);
5555  }
5556 }
5557 
5558 // ---------------------------------------------------------------------------
5559 
5560 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5561 {
5562  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5563  AnsiString(VLoc));
5564  THVPair TrackMapKeyPair;
5565  TTrackMapIterator TrackMapPtr;
5566 
5567  TrackMapKeyPair.first = HLoc;
5568  TrackMapKeyPair.second = VLoc;
5569  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5570  if(TrackMapPtr == TrackMap.end())
5571  {
5572  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5573  throw Exception(Message);
5574  }
5575  else
5576  {
5577  Utilities->CallLogPop(1943);
5578  return(TrackElementAt(871, TrackMapPtr->second));
5579  }
5580 }
5581 
5582 // ---------------------------------------------------------------------------
5583 
5584 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap Map, TTrackVector Vector) //new at v2.9.0 for clipboard pref dirs
5585 {
5586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5587  AnsiString(VLoc));
5588  THVPair MapKeyPair;
5589  TTrackMapIterator MapPtr;
5590 
5591  MapKeyPair.first = HLoc;
5592  MapKeyPair.second = VLoc;
5593  MapPtr = Map.find(MapKeyPair);
5594  if(MapPtr == Map.end())
5595  {
5596  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5597  throw Exception(Message);
5598  }
5599  else
5600  {
5601  Utilities->CallLogPop(2280);
5602  return(Vector.at(MapPtr->second));
5603  }
5604 }
5605 
5606 // ---------------------------------------------------------------------------
5607 
5609 {
5610  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5611  AnsiString(VLoc));
5612  THVPair InactiveTrackMapKeyPair;
5613  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5614 
5615  InactiveTrackMapKeyPair.first = HLoc;
5616  InactiveTrackMapKeyPair.second = VLoc;
5617  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5618  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5619  {
5620  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5621  throw Exception(Message);
5622  }
5623  else
5624  {
5625  Utilities->CallLogPop(1949);
5626  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5627  }
5628 }
5629 
5630 // ---------------------------------------------------------------------------
5631 
5632 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5633 {
5634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5635  bool Present = true;
5636  THVPair TrackMapKeyPair;
5637  TTrackMapIterator TrackMapPtr;
5638 
5639  TrackMapKeyPair.first = HLoc;
5640  TrackMapKeyPair.second = VLoc;
5641  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5642  if(TrackMapPtr == TrackMap.end())
5643  {
5644  Present = false;
5645  }
5646  Utilities->CallLogPop(2057);
5647  return(Present);
5648 }
5649 
5650 // ---------------------------------------------------------------------------
5651 
5652 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5653 {
5654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5655  AnsiString(VLoc));
5656  bool Present = true;
5657  THVPair InactiveTrackMapKeyPair;
5658  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5659 
5660  InactiveTrackMapKeyPair.first = HLoc;
5661  InactiveTrackMapKeyPair.second = VLoc;
5662  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5663  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5664  {
5665  Present = false;
5666  }
5667  Utilities->CallLogPop(2058);
5668  return(Present);
5669 }
5670 
5671 // ---------------------------------------------------------------------------
5672 
5673 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5674 // max number of elements is 2, for platforms
5675 // note that both elements of RetPair may be the same, if only one present in map
5676 {
5677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5678  AnsiString(VLoc));
5679  THVPair InactiveTrackMapKeyPair;
5680  TIMPair RetPair;
5681  TInactiveTrackRange InactiveTrackRange;
5682 
5683  FoundFlag = false;
5684  InactiveTrackMapKeyPair.first = HLoc;
5685  InactiveTrackMapKeyPair.second = VLoc;
5686  if(InactiveTrack2MultiMap.empty())
5687  {
5688  RetPair.first = 0;
5689  RetPair.second = 0;
5690  Utilities->CallLogPop(1815);
5691  return(RetPair); // map empty
5692  }
5693  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5694  if(InactiveTrackRange.first == InactiveTrackRange.second)
5695  {
5696  RetPair.first = 0;
5697  RetPair.second = 0;
5698  Utilities->CallLogPop(514);
5699  return(RetPair); // nothing found
5700  }
5701  else
5702  {
5703  RetPair.first = InactiveTrackRange.first->second;
5704  RetPair.second = (--InactiveTrackRange.second)->second;
5705  FoundFlag = true;
5706  Utilities->CallLogPop(515);
5707  return(RetPair);
5708  }
5709 }
5710 
5711 // ---------------------------------------------------------------------------
5712 
5713 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5714 {
5715 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5716  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5717  AnsiString(DivergingPosition));
5718  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5719  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5720  int SpeedTag1 = T1.SpeedTag;
5721  int SpeedTag2 = T2.SpeedTag;
5722 
5723  if(T1.Attribute != T2.Attribute)
5724  {
5725  Utilities->CallLogPop(516);
5726  return(false);
5727  }
5728  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5729  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5730  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5731  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5732  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5733  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5734  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5735  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5736  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5737  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5738  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5739  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5740  {
5741  Utilities->CallLogPop(517);
5742  return(true);
5743  }
5744  else
5745  {
5746  Utilities->CallLogPop(518);
5747  return(false);
5748  }
5749 }
5750 
5751 // ---------------------------------------------------------------------------
5752 
5753 /*
5754  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5755  {
5756  if(lower.second < higher.second) return true;
5757  else if(lower.second > higher.second) return false;
5758  else if(lower.second == higher.second)
5759  {
5760  if(lower.first < higher.first) return true;
5761  }
5762  return false;
5763  }
5764 */
5765 // ---------------------------------------------------------------------------
5766 
5767 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5768 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5769 {
5770  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5771  if(TrackElement.TrackType != GapJump)
5772  {
5773  throw Exception("Error, Wrong track type in PlotGap");
5774  }
5775  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5776  {
5777  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5778  }
5779  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5780  {
5781  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5782  }
5783  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5784  {
5785  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5786  }
5787  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5788  {
5789  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5790  }
5791  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5792  {
5793  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5794  }
5795  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5796  {
5797  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5798  }
5799  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5800  {
5801  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5802  }
5803  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5804  {
5805  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5806  }
5807  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5808  {
5809  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5810  }
5811  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5812  {
5813  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5814  }
5815  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5816  {
5817  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5818  }
5819  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5820  {
5821  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5822  }
5823  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5824  {
5825  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5826  }
5827  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5828  {
5829  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5830  }
5831  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5832  {
5833  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5834  }
5835  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5836  {
5837  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5838  }
5839  Utilities->CallLogPop(1101);
5840 }
5841 
5842 // ---------------------------------------------------------------------------
5843 
5844 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5845 {
5846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5847  if(TrackElement.TrackType != Points)
5848  {
5849  throw Exception("Error, Wrong track type in PlotPoints");
5850  }
5851  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5852  TrackElement.PlotVariableTrackElement(4, Disp);
5853  if(BothFillets)
5854  {
5855  if(TrackElement.SpeedTag < 28)
5856  {
5857  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5858  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5859  }
5860  else if(TrackElement.SpeedTag < 132)
5861  {
5862  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5863  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5864  }
5865  else
5866  {
5867  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5868  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5869  }
5870  }
5871  else
5872  {
5873  if(TrackElement.SpeedTag < 28)
5874  {
5875  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5876  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5877  }
5878  else if(TrackElement.SpeedTag < 132)
5879  {
5880  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5881  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5882  }
5883  else
5884  {
5885  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5886  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5887  }
5888  }
5889 // replot platform if required
5890  TIMPair IMPair;
5891  bool FoundFlag;
5892 
5893  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5894  if(FoundFlag)
5895  {
5896  // only one platform possible at points so only need to plot IMPair.first
5897  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5898  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5899  }
5900  Utilities->CallLogPop(519);
5901 }
5902 
5903 // ---------------------------------------------------------------------------
5904 
5905 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5906 {
5907 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5909  if(TrackElement.TrackType != SignalPost)
5910  {
5911  throw Exception("Error, Wrong track type in PlotSignal");
5912  }
5913  for(int x = 0; x < 40; x++)
5914  {
5915  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5916  {
5917  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5918  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5919 // in case existing signal is a double yellow
5920  // plot platforms if present
5921 // Graphics::TBitmap* SignalPlatformGraphic;
5922 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5923 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5924 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5925 // to not be plotted with the above function.
5926  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5927  // now plot signal (double yellow overwrites most of signal platform if present)
5928  // additions at version 0.6 for other aspects & ground sigs
5929  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5930  {
5931  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5932  }
5933  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5934  {
5935  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5936  }
5937  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5938  {
5939  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5940  }
5941  else // 4 aspect
5942  {
5943  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5944  }
5945  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5946  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5947  {
5948  if(TrackElement.SpeedTag == 68)
5949  {
5950  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5951  }
5952  if(TrackElement.SpeedTag == 69)
5953  {
5954  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5955  }
5956  if(TrackElement.SpeedTag == 70)
5957  {
5958  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5959  }
5960  if(TrackElement.SpeedTag == 71)
5961  {
5962  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5963  }
5964  if(TrackElement.SpeedTag == 72)
5965  {
5966  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5967  }
5968  if(TrackElement.SpeedTag == 73)
5969  {
5970  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5971  }
5972  if(TrackElement.SpeedTag == 74)
5973  {
5974  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5975  }
5976  if(TrackElement.SpeedTag == 75)
5977  {
5978  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5979  }
5980  }
5981  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5982  // ground signal calling on, need to use normal proceed aspect
5983  {
5984  for(int x = 0; x < 40; x++)
5985  {
5986  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5987  {
5988  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5989  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5990  // plot special signal platform if present
5991  Graphics::TBitmap* SignalPlatformGraphic;
5992  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5993  // now plot signal
5994  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5995  }
5996  }
5997  }
5998  break;
5999  }
6000  }
6001  Utilities->CallLogPop(520);
6002 }
6003 
6004 // ---------------------------------------------------------------------------
6005 
6006 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6007 {
6008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6009  bool FoundFlag;
6010  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6011 
6012  if(!FoundFlag)
6013  {
6014  Utilities->CallLogPop(2112);
6015  return;
6016  }
6017  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6018  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6019 
6020  // don't want 'else if' for the below as may need to plot 2 platforms
6021  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6022  {
6023  if(IAElement1.LocationName == "") // '2' will be same
6024  {
6025  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6026  }
6027  else
6028  {
6029  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6030  }
6031  }
6032  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6033  {
6034  if(IAElement1.LocationName == "") // '2' will be same
6035  {
6036  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6037  }
6038  else
6039  {
6040  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6041  }
6042  }
6043  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6044  {
6045  if(IAElement1.LocationName == "") // '2' will be same
6046  {
6047  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6048  }
6049  else
6050  {
6051  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6052  }
6053  }
6054  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6055  {
6056  if(IAElement1.LocationName == "") // '2' will be same
6057  {
6058  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6059  }
6060  else
6061  {
6062  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6063  }
6064  }
6065  Utilities->CallLogPop(2113);
6066 }
6067 
6068 // ---------------------------------------------------------------------------
6069 
6070 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6071 {
6072 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6073  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6074  AnsiString(VLoc));
6075 // find topmost LC, opening them all (to trains) in turn
6076  int UpStep = 0;
6077 
6078  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6079  {
6080  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6081  UpStep--;
6082  }
6083 // now find bottommost LC, opening them all (to trains) in turn
6084  int DownStep = 1;
6085 
6086  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6087  {
6088  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6089  DownStep++;
6090  }
6091 // find leftmost LC, opening them all (to trains) in turn
6092  int LeftStep = 0;
6093 
6094  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6095  {
6096  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6097  LeftStep--;
6098  }
6099 // now find rightmost LC, opening them all (to trains) in turn
6100  int RightStep = 1;
6101 
6102  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6103  {
6104  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6105  RightStep++;
6106  }
6107  Utilities->CallLogPop(1915);
6108 }
6109 
6110 // ---------------------------------------------------------------------------
6111 
6112 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6113 {
6114  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6115 // work upwards setting all to manual
6116  int UpStep = -1;
6117 
6118  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6119  {
6120  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6121  UpStep--;
6122  }
6123 // work downwards setting all to manual
6124  int DownStep = 1;
6125 
6126  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6127  {
6128  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6129  DownStep++;
6130  }
6131 // work leftwards setting all to manual
6132  int LeftStep = -1;
6133 
6134  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6135  {
6136  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6137  LeftStep--;
6138  }
6139 // work rightwards setting all to manual
6140  int RightStep = 1;
6141 
6142  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6143  {
6144  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6145  RightStep++;
6146  }
6147  Utilities->CallLogPop(2242);
6148 }
6149 
6150 // ---------------------------------------------------------------------------
6151 
6152 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6153 {
6154  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6156  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6157  {
6158  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6159  {
6160  BarriersDownVector.at(x).TypeOfRoute = 2;
6161  break;
6162  }
6163  }
6164  Utilities->CallLogPop(2243);
6165 }
6166 
6167 // ---------------------------------------------------------------------------
6168 
6169 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6170 {
6171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6172 // work upwards
6173  int UpStep = 0; //start with this location
6174 
6175  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6176  {
6177  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6178  {
6179  Utilities->CallLogPop(2244);
6180  return(true);
6181  }
6182  UpStep--;
6183  }
6184 // work downwards
6185  int DownStep = 1;
6186 
6187  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6188  {
6189  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6190  {
6191  Utilities->CallLogPop(2245);
6192  return(true);
6193  }
6194  DownStep++;
6195  }
6196 // work leftwards
6197  int LeftStep = -1;
6198 
6199  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6200  {
6201  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6202  {
6203  Utilities->CallLogPop(2246);
6204  return(true);
6205  }
6206  LeftStep--;
6207  }
6208 // work rightwards
6209  int RightStep = 1;
6210 
6211  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6212  {
6213  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6214  {
6215  Utilities->CallLogPop(2247);
6216  return(true);
6217  }
6218  RightStep++;
6219  }
6220  Utilities->CallLogPop(2248);
6221  return(false);
6222 }
6223 
6224 // ---------------------------------------------------------------------------
6225 
6226 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6227 {
6228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6229  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6230  {
6231  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6232  {
6233  BDVectorPos = x;
6234  Utilities->CallLogPop(2249);
6235  return(true);
6236  }
6237  }
6238  BDVectorPos = -1;
6239  Utilities->CallLogPop(2250);
6240  return(false);
6241 }
6242 
6243 // ---------------------------------------------------------------------------
6244 
6245 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6246 // open to trains
6247 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6248 {
6249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6250  AnsiString(VLoc));
6251  if(!IsLCAtHV(4, HLoc, VLoc))
6252  {
6253  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6254  }
6255  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6256  {
6257  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6258  }
6259 // check for adjacent LCs & if so open (to trains)
6260  if(BaseElementSpeedTag == 1) // hor track element
6261  {
6262  // find topmost LC, opening them all (to trains) in turn
6263  int UpStep = 0;
6264  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6265  {
6266  UpStep--;
6267  }
6268  UpStep++;
6269  // now find bottommost LC, opening them all (to trains) in turn
6270  int DownStep = 1;
6271  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6272  {
6273  DownStep++;
6274  }
6275  DownStep--;
6276  // now plot graphics, UpStep is smallest & DownStep largest
6277  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6278  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6279  Graphics::TBitmap *RouteGraphic;
6280  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6281  if(TypeOfRoute == 1)
6282  {
6283  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6284  }
6285  else if(TypeOfRoute == 0)
6286  {
6287  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6288  }
6289  else //manual - no route
6290  {
6291  RouteGraphic = BaseGraphic;
6292  }
6293 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6294 // LinkSigRouteGraphicsPtr[1] ver }
6295 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6296 // LinkNonSigRouteGraphicsPtr[1] ver }
6297 
6298  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6299  {
6300  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6301  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6302  if(!Manual)
6303  {
6304  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6305  }
6306  else
6307  {
6308  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6309  }
6310  }
6311  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6312  {
6313  if(UpStep == 0)
6314  {
6315  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6316  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6317  if(!Manual)
6318  {
6319  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6320  }
6321  else
6322  {
6323  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6324  }
6325  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6326  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6327  if(!Manual)
6328  {
6329  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6330  }
6331  else
6332  {
6333  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6334  }
6335  }
6336  else
6337  {
6338  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6339  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6340  if(!Manual)
6341  {
6342  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6343  }
6344  else
6345  {
6346  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6347  }
6348  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6349  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6350  if(!Manual)
6351  {
6352  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6353  }
6354  else
6355  {
6356  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6357  }
6358  }
6359  }
6360  else // at least one plain graphic
6361  {
6362  if(UpStep == 0)
6363  {
6364  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6365  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6366  if(!Manual)
6367  {
6368  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6369  }
6370  else
6371  {
6372  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6373  }
6374  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6375  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6376  if(!Manual)
6377  {
6378  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6379  }
6380  else
6381  {
6382  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6383  }
6384  }
6385  else if(DownStep == 0)
6386  {
6387  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6388  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6389  if(!Manual)
6390  {
6391  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6392  }
6393  else
6394  {
6395  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6396  }
6397  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6398  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6399  if(!Manual)
6400  {
6401  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6402  }
6403  else
6404  {
6405  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6406  }
6407  }
6408  else
6409  {
6410  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6411  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6412  if(!Manual)
6413  {
6414  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6415  }
6416  else
6417  {
6418  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6419  }
6420  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6421  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6422  if(!Manual)
6423  {
6424  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6425  }
6426  else
6427  {
6428  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6429  }
6430  }
6431  for(int x = (UpStep + 1); x < DownStep; x++)
6432  {
6433  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6434  if(x == 0)
6435  {
6436  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6437  }
6438  else
6439  {
6440  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6441  }
6442  if(!Manual)
6443  {
6444  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6445  }
6446  else
6447  {
6448  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6449  }
6450  }
6451  }
6452  Disp->Update();
6453  Utilities->CallLogPop(1958);
6454  return;
6455  }
6456 
6457  else // ver track element
6458  {
6459  // find leftmost LC, opening them all (to trains) in turn
6460  int LStep = 0;
6461  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6462  {
6463  LStep--;
6464  }
6465  LStep++;
6466  // now find rightmost LC, opening them all (to trains) in turn
6467  int RStep = 1;
6468  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6469  {
6470  RStep++;
6471  }
6472  RStep--;
6473  // now plot graphics, LStep is smallest & RStep largest
6474  Graphics::TBitmap *RouteGraphic;
6475  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6476  if(TypeOfRoute == 1)
6477  {
6478  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6479  }
6480  else if(TypeOfRoute == 0)
6481  {
6482  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6483  }
6484  else //manual
6485  {
6486  RouteGraphic = BaseGraphic;
6487  }
6488 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6489 // LinkSigRouteGraphicsPtr[1] ver }
6490 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6491 // LinkNonSigRouteGraphicsPtr[1] ver }
6492  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6493  {
6494  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6495  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6496  if(!Manual)
6497  {
6498  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6499  }
6500  else
6501  {
6502  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6503  }
6504  }
6505  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6506  {
6507  if(LStep == 0)
6508  {
6509  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6510  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6511  if(!Manual)
6512  {
6513  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6514  }
6515  else
6516  {
6517  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6518  }
6519  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6520  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6521  if(!Manual)
6522  {
6523  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6524  }
6525  else
6526  {
6527  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6528  }
6529  }
6530  else
6531  {
6532  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6533  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6534  if(!Manual)
6535  {
6536  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6537  }
6538  else
6539  {
6540  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6541  }
6542  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6543  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6544  if(!Manual)
6545  {
6546  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6547  }
6548  else
6549  {
6550  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6551  }
6552  }
6553  }
6554  else // at least one plain graphic
6555  {
6556  if(LStep == 0)
6557  {
6558  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6559  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6560  if(!Manual)
6561  {
6562  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6563  }
6564  else
6565  {
6566  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6567  }
6568  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6569  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6570  if(!Manual)
6571  {
6572  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6573  }
6574  else
6575  {
6576  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6577  }
6578  }
6579  else if(RStep == 0)
6580  {
6581  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6582  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6583  if(!Manual)
6584  {
6585  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6586  }
6587  else
6588  {
6589  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6590  }
6591  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6592  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6593  if(!Manual)
6594  {
6595  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6596  }
6597  else
6598  {
6599  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6600  }
6601  }
6602  else
6603  {
6604  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6605  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6606  if(!Manual)
6607  {
6608  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6609  }
6610  else
6611  {
6612  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6613  }
6614  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6615  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6616  if(!Manual)
6617  {
6618  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6619  }
6620  else
6621  {
6622  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6623  }
6624  }
6625  for(int x = (LStep + 1); x < RStep; x++)
6626  {
6627  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6628  if(x == 0)
6629  {
6630  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6631  }
6632  else
6633  {
6634  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6635  }
6636  if(!Manual)
6637  {
6638  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6639  }
6640  else
6641  {
6642  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6643  }
6644  }
6645  }
6646  Disp->Update();
6647  Utilities->CallLogPop(1896);
6648  return;
6649  }
6650 }
6651 
6652 // ---------------------------------------------------------------------------
6653 
6654 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6655 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6656 {
6657  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6658  AnsiString(HLoc) + "," + AnsiString(VLoc));
6659  if(!IsLCAtHV(29, HLoc, VLoc))
6660  {
6661  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6662  }
6663  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6664  {
6665  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6666  }
6667 // check for adjacent LCs & if so open (to trains)
6668  if(BaseElementSpeedTag == 1) // hor track element
6669  {
6670  // find topmost LC, opening them all (to trains) in turn
6671  int UpStep = 0;
6672  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6673  {
6674  UpStep--;
6675  }
6676  UpStep++;
6677  // now find bottommost LC, opening them all (to trains) in turn
6678  int DownStep = 1;
6679  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6680  {
6681  DownStep++;
6682  }
6683  DownStep--;
6684  // now plot graphics, UpStep is smallest & DownStep largest
6685  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6686  {
6687  if(!Manual)
6688  {
6689  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6690  }
6691  else
6692  {
6693  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6694  }
6695  }
6696  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6697  {
6698  if(!Manual)
6699  {
6700  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6701  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6702  }
6703  else
6704  {
6705  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6706  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6707  }
6708  }
6709  else // at least one plain graphic
6710  {
6711  if(!Manual)
6712  {
6713  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6714  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6715  for(int x = (UpStep + 1); x < DownStep; x++)
6716  {
6717  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6718  }
6719  }
6720  else
6721  {
6722  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6723  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6724  for(int x = (UpStep + 1); x < DownStep; x++)
6725  {
6726  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6727  }
6728  }
6729  }
6730  // set markers
6731  for(int x = UpStep; x <= DownStep; x++)
6732  {
6733  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6734  }
6735  Display->Update();
6736  Utilities->CallLogPop(1944);
6737  return;
6738  }
6739 
6740  else // ver track element
6741  {
6742  // find leftmost LC, opening them all (to trains) in turn
6743  int LStep = 0;
6744  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6745  {
6746  LStep--;
6747  }
6748  LStep++;
6749  // now find rightmost LC, opening them all (to trains) in turn
6750  int RStep = 1;
6751  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6752  {
6753  RStep++;
6754  }
6755  RStep--;
6756  // now plot graphics, LStep is smallest & RStep largest
6757  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6758  {
6759  if(!Manual)
6760  {
6761  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6762  }
6763  else
6764  {
6765  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6766  }
6767  }
6768  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6769  {
6770  if(!Manual)
6771  {
6772  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6773  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6774  }
6775  else
6776  {
6777  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6778  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6779  }
6780  }
6781  else // at least one plain graphic
6782  {
6783  if(!Manual)
6784  {
6785  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6786  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6787  for(int x = (LStep + 1); x < RStep; x++)
6788  {
6789  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6790  }
6791  }
6792  else
6793  {
6794  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6795  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6796  for(int x = (LStep + 1); x < RStep; x++)
6797  {
6798  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6799  }
6800  }
6801  }
6802  // set markers
6803  for(int x = LStep; x <= RStep; x++)
6804  {
6805  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6806  }
6807  Disp->Update();
6808  Utilities->CallLogPop(1945);
6809  return;
6810  }
6811 }
6812 
6813 // ---------------------------------------------------------------------------
6814 
6815 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6816 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6817 {
6818  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6819  AnsiString(VLoc));
6820  if(!IsLCAtHV(9, HLoc, VLoc))
6821  {
6822  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6823  }
6824  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6825  {
6826  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6827  }
6828 // check for adjacent LCs & if so close (to trains)
6829  if(BaseElementSpeedTag == 1) // hor track element
6830  {
6831  // find topmost LC, closing them all (to trains) in turn
6832  int UpStep = 0;
6833  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6834  {
6835  UpStep--;
6836  }
6837  UpStep++;
6838  // now find bottommost LC, opening them all (to trains) in turn
6839  int DownStep = 1;
6840  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6841  {
6842  DownStep++;
6843  }
6844  DownStep--;
6845  // now plot graphics, UpStep is smallest & DownStep largest
6846  for(int x = UpStep; x < (DownStep + 1); x++)
6847  {
6848  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6849  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6850  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6851  }
6852  Disp->Update();
6853  Utilities->CallLogPop(1959);
6854  return;
6855  }
6856 
6857  else // ver track element
6858  {
6859  // find leftmost LC, closing them all (to trains) in turn
6860  int LStep = 0;
6861  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6862  {
6863  LStep--;
6864  }
6865  LStep++;
6866  // now find rightmost LC, opening them all (to trains) in turn
6867  int RStep = 1;
6868  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6869  {
6870  RStep++;
6871  }
6872  RStep--;
6873  // now plot graphics, LStep is smallest & RStep largest
6874  for(int x = LStep; x < (RStep + 1); x++)
6875  {
6876  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6877  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6878  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6879  }
6880  Disp->Update();
6881  Utilities->CallLogPop(1960);
6882  return;
6883  }
6884 }
6885 
6886 // ---------------------------------------------------------------------------
6887 
6888 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6889 // closed to trains
6890 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6891 {
6892  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6893  AnsiString(HLoc) + "," + AnsiString(VLoc));
6894  if(!IsLCAtHV(34, HLoc, VLoc))
6895  {
6896  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6897  }
6898  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6899  {
6900  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6901  }
6902  TTrackElement TE;
6903 
6904 // check for adjacent LCs & if so close (to trains)
6905  if(BaseElementSpeedTag == 1) // hor track element
6906  {
6907  // find topmost LC, closing them all (to trains) in turn
6908  int UpStep = 0;
6909  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6910  {
6911  UpStep--;
6912  }
6913  UpStep++;
6914  // now find bottommost LC, opening them all (to trains) in turn
6915  int DownStep = 1;
6916  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6917  {
6918  DownStep++;
6919  }
6920  DownStep--;
6921  // now plot graphics, UpStep is smallest & DownStep largest
6922  for(int x = UpStep; x <= DownStep; x++)
6923  {
6924  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6925  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6926  }
6927  Display->Update();
6928  Utilities->CallLogPop(1946);
6929  return;
6930  }
6931 
6932  else // ver track element
6933  {
6934  // find leftmost LC, closing them all (to trains) in turn
6935  int LStep = 0;
6936  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6937  {
6938  LStep--;
6939  }
6940  LStep++;
6941  // now find rightmost LC, opening them all (to trains) in turn
6942  int RStep = 1;
6943  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6944  {
6945  RStep++;
6946  }
6947  RStep--;
6948  // now plot graphics, LStep is smallest & RStep largest
6949  for(int x = LStep; x <= RStep; x++)
6950  {
6951  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6952  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6953  }
6954  Display->Update();
6955  Utilities->CallLogPop(1947);
6956  return;
6957  }
6958 }
6959 
6960 // ---------------------------------------------------------------------------
6961 
6962 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
6963 {
6964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6965  Graphics::TBitmap *RouteGraphic;
6966  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6967 
6968  if(BaseElementSpeedTag == 1)
6969  {
6970  if(TypeOfRoute == 1)
6971  {
6972  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6973  }
6974  else if(TypeOfRoute == 0)
6975  {
6976  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6977  }
6978  else //manual
6979  {
6980  RouteGraphic = BaseGraphic;
6981  }
6982  if(State == Raising)
6983  {
6984  RouteGraphic = BaseGraphic;
6985  }
6986  }
6987  else
6988  {
6989  BaseGraphic = RailGraphics->gl2;
6990  if(TypeOfRoute == 1)
6991  {
6992  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6993  }
6994  else if(TypeOfRoute == 0)
6995  {
6996  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6997  }
6998  else
6999  {
7000  RouteGraphic = BaseGraphic; //manual
7001  }
7002  if(State == Raising)
7003  {
7004  RouteGraphic = BaseGraphic;
7005  }
7006  }
7007  int UpStep = 0;
7008 
7009  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7010  {
7011  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7012  if(UpStep == 0)
7013  {
7014  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7015  }
7016  else
7017  {
7018  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7019  }
7020  UpStep--;
7021  }
7022 // now find bottommost LC, opening them all (to trains) in turn
7023  int DownStep = 1;
7024 
7025  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7026  {
7027  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7028  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7029  DownStep++;
7030  }
7031  int LeftStep = 0;
7032 
7033  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7034  {
7035  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7036  if(LeftStep == 0)
7037  {
7038  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7039  }
7040  else
7041  {
7042  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7043  }
7044  LeftStep--;
7045  }
7046 // now find rightmost LC, opening them all (to trains) in turn
7047  int RightStep = 1;
7048 
7049  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7050  {
7051  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7052  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7053  RightStep++;
7054  }
7055  Disp->Update();
7056  Utilities->CallLogPop(1914);
7057 }
7058 
7059 // ---------------------------------------------------------------------------
7060 
7061 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7062 {
7063 // return false for no LC there, flashing or a closed (to trains) LC
7064  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7065  bool FoundFlag;
7066  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7067 
7068  if(!FoundFlag)
7069  {
7070  Utilities->CallLogPop(1898);
7071  return(false);
7072  }
7073  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7074  {
7075  Utilities->CallLogPop(1899);
7076  return(false);
7077  }
7078  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7079  {
7080  Utilities->CallLogPop(1900);
7081  return(true);
7082  }
7083  Utilities->CallLogPop(1901);
7084  return(false);
7085 }
7086 
7087 // ---------------------------------------------------------------------------
7088 
7089 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7090 {
7091 // return false for no LC there, flashing LC or open (to trains) LC
7092  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7093  bool FoundFlag;
7094  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7095 
7096  if(!FoundFlag)
7097  {
7098  Utilities->CallLogPop(1922);
7099  return(false);
7100  }
7101  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7102  {
7103  Utilities->CallLogPop(1923);
7104  return(false);
7105  }
7106  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7107  {
7108  Utilities->CallLogPop(1924);
7109  return(true);
7110  }
7111  Utilities->CallLogPop(1925);
7112  return(false);
7113 }
7114 
7115 // ---------------------------------------------------------------------------
7116 
7117 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7118 {
7119 // return true for barrier in process of moving
7120  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7121  bool FoundFlag;
7122  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7123 
7124  if(!FoundFlag)
7125  {
7126  Utilities->CallLogPop(1918);
7127  return(false);
7128  }
7129  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7130  {
7131  Utilities->CallLogPop(1919);
7132  return(false);
7133  }
7134  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7135  {
7136  Utilities->CallLogPop(1920);
7137  return(true);
7138  }
7139  Utilities->CallLogPop(1921);
7140  return(false);
7141 }
7142 
7143 // ---------------------------------------------------------------------------
7144 
7145 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7146 {
7147 // return true for an LC at H&V
7148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7149  bool FoundFlag;
7150  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7151 
7152  if(!FoundFlag)
7153  {
7154  Utilities->CallLogPop(1902);
7155  return(false);
7156  }
7157  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7158  {
7159  Utilities->CallLogPop(1903);
7160  return(false);
7161  }
7162  Utilities->CallLogPop(1904);
7163  return(true);
7164 }
7165 
7166 // ---------------------------------------------------------------------------
7167 
7168 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7169 {
7170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7171  AnsiString(Attr));
7172  bool FoundFlag;
7173  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7174 
7175  if(!FoundFlag)
7176  {
7177  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7178  }
7179  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7180  {
7181  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7182  }
7183  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7184  Utilities->CallLogPop(1905);
7185  return;
7186 }
7187 
7188 // ---------------------------------------------------------------------------
7189 
7191 {
7192  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7193  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7194  {
7195  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
7196  if(InactiveTrackElement.TrackType == LevelCrossing)
7197  {
7198  InactiveTrackVector.at(x).Attribute = 0;
7199  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7200  }
7201  }
7202  Utilities->CallLogPop(1913);
7203  return;
7204 }
7205 
7206 // ---------------------------------------------------------------------------
7207 
7208 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7209 {
7210 // return true if there is either a route set or being set on any element or a train on any element
7211  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7212  "," + AnsiString(VLoc));
7213 
7214  THVPair TrackMapKeyPair;
7215  TTrack::TTrackMapIterator TrackMapPtr;
7216  int DummyRouteNumber;
7217 
7218  TrainPresent = false;
7219 // find topmost LC, checking each for routes & trains
7220  int UpStep = 0;
7221 
7222  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7223  {
7224  TrackMapKeyPair.first = HLoc;
7225  TrackMapKeyPair.second = VLoc + UpStep;
7226  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7227  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7228  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7229  {
7230  Utilities->CallLogPop(1932);
7231  return(true);
7232  }
7233  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7234  {
7235  TrainPresent = true;
7236  Utilities->CallLogPop(1933);
7237  return(true);
7238  }
7239  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7240  {
7241  Utilities->CallLogPop(2274);
7242  return(true);
7243  }
7244  UpStep--;
7245  }
7246 // now find bottommost LC, opening them all (to trains) in turn
7247  int DownStep = 1;
7248 
7249  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7250  {
7251  TrackMapKeyPair.first = HLoc;
7252  TrackMapKeyPair.second = VLoc + DownStep;
7253  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7254  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7255  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7256  {
7257  Utilities->CallLogPop(1934);
7258  return(true);
7259  }
7260  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7261  {
7262  TrainPresent = true;
7263  Utilities->CallLogPop(1935);
7264  return(true);
7265  }
7266  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7267  {
7268  Utilities->CallLogPop(2275);
7269  return(true);
7270  }
7271  DownStep++;
7272  }
7273 // find leftmost LC
7274  int LeftStep = 0;
7275 
7276  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7277  {
7278  TrackMapKeyPair.first = HLoc + LeftStep;
7279  TrackMapKeyPair.second = VLoc;
7280  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7281  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7282  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7283  {
7284  Utilities->CallLogPop(1936);
7285  return(true);
7286  }
7287  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7288  {
7289  TrainPresent = true;
7290  Utilities->CallLogPop(1937);
7291  return(true);
7292  }
7293  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7294  {
7295  Utilities->CallLogPop(2276);
7296  return(true);
7297  }
7298  LeftStep--;
7299  }
7300 // now find rightmost LC, opening them all (to trains) in turn
7301  int RightStep = 1;
7302 
7303  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7304  {
7305  TrackMapKeyPair.first = HLoc + RightStep;
7306  TrackMapKeyPair.second = VLoc;
7307  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7308  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7309  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7310  {
7311  Utilities->CallLogPop(1938);
7312  return(true);
7313  }
7314  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7315  {
7316  TrainPresent = true;
7317  Utilities->CallLogPop(1939);
7318  return(true);
7319  }
7320  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7321  {
7322  Utilities->CallLogPop(2277);
7323  return(true);
7324  }
7325  RightStep++;
7326  }
7327  Utilities->CallLogPop(1940);
7328  return(false);
7329 }
7330 
7331 // ---------------------------------------------------------------------------
7332 
7333 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7334 {
7335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7336  for(unsigned int x = 0; x < SearchVector.size(); x++)
7337  {
7338  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7339  {
7340  Utilities->CallLogPop(2278);
7341  return true;
7342  }
7343  }
7344  Utilities->CallLogPop(2279);
7345  return false;
7346 }
7347 
7348 // ---------------------------------------------------------------------------
7349 
7350 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7351 {
7352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7353  AnsiString(HLoc) + "," + AnsiString(VLoc));
7354  if(!IsLCAtHV(60, HLoc, VLoc))
7355  {
7356  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7357  }
7358 
7359 // check for adjacent LCs
7360  // find topmost LC
7361  int UpStep = 0;
7362  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7363  {
7364  UpStep--;
7365  }
7366  UpStep++;
7367  // now find bottommost LC, opening them all (to trains) in turn
7368  int DownStep = 1;
7369  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7370  {
7371  DownStep++;
7372  }
7373  DownStep--;
7374  // now plot graphics, UpStep is smallest & DownStep largest
7375  for(int x = UpStep; x <= DownStep; x++)
7376  {
7377  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7378  }
7379 
7380  // find leftmost LC, closing them all (to trains) in turn
7381  int LStep = 0;
7382  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7383  {
7384  LStep--;
7385  }
7386  LStep++;
7387  // now find rightmost LC, opening them all (to trains) in turn
7388  int RStep = 1;
7389  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7390  {
7391  RStep++;
7392  }
7393  RStep--;
7394  // now plot graphics, LStep is smallest & RStep largest
7395  for(int x = LStep; x <= RStep; x++)
7396  {
7397  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7398  }
7399  Display->Update();
7400  Utilities->CallLogPop(2315);
7401  return;
7402 }
7403 
7404 // ---------------------------------------------------------------------------
7405 
7406 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7407 {
7408  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7409  if(TrackElement.TrackType != Points)
7410  {
7411  throw Exception("Error, Wrong track type in GetFilletGraphic");
7412  }
7413  if(TrackElement.SpeedTag < 28)
7414  {
7415  Utilities->CallLogPop(521);
7416  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7417  }
7418  else if(TrackElement.SpeedTag < 132)
7419  {
7420  Utilities->CallLogPop(522);
7421 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7422  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7423  }
7424  else
7425  {
7426  Utilities->CallLogPop(1537);
7427  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7428  }
7429 }
7430 
7431 // ---------------------------------------------------------------------------
7432 
7434 {
7435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7436  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7437  {
7438  TrackVector.at(x).TrainIDOnElement = -1;
7439  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
7440  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
7441  }
7442  Utilities->CallLogPop(1342);
7443 }
7444 
7445 // ---------------------------------------------------------------------------
7446 
7447 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7448 /*
7449  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7450 */
7451 {
7452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7453  AnsiString(ScreenPosV));
7454  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7455  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7456 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7457  Utilities->CallLogPop(535);
7458 }
7459 
7460 // ---------------------------------------------------------------------------
7461 
7462 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7463 /*
7464  Converts the screen position to the true (without offsets) position
7465 */
7466 {
7467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7468  AnsiString(ScreenPosV));
7469  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7470  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7471  Utilities->CallLogPop(536);
7472 }
7473 
7474 // ---------------------------------------------------------------------------
7475 
7476 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7477 {
7478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7479  AnsiString(VPosTrue));
7480  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7481  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7482  Utilities->CallLogPop(537);
7483 }
7484 
7485 // ---------------------------------------------------------------------------
7486 
7487 void TTrack::CheckMapAndTrack(int Caller) // test
7488 {
7489  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7490  int Zeroes = 0;
7491  bool FoundFlag;
7492 
7493  for(unsigned int a = 0; a < TrackVector.size(); a++)
7494  {
7495  TTrackElement CheckElement = Track->TrackVector.at(a);
7496  if(CheckElement.SpeedTag == 0)
7497  {
7498  Zeroes++; // zeroed elements not saved in map
7499  }
7500  else
7501  {
7502  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7503  if(!FoundFlag)
7504  {
7505  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7506  " in TrackMap, Caller=" + (AnsiString)Caller);
7507  }
7508  if(MapVecPos != (int)a)
7509  {
7510  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7511  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7512  (AnsiString)Caller);
7513  }
7514  }
7515  }
7516  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7517  {
7518  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7519  " Caller=" + (AnsiString)Caller);
7520  }
7521  Utilities->CallLogPop(538);
7522  return;
7523 }
7524 
7525 // ---------------------------------------------------------------------------
7526 
7527 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7528 {
7529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7530  bool FoundFlag;
7531  TIMPair InactivePair;
7532 
7533  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7534  {
7535  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
7536  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7537  if(!FoundFlag)
7538  {
7539  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7540  " in InactiveMap, Caller=" + (AnsiString)Caller);
7541  }
7542  if((InactivePair.first != a) && (InactivePair.second != a))
7543  {
7544  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7545  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7546  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7547  }
7548  }
7549  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7550  {
7551  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7552  " Caller=" + (AnsiString)Caller);
7553  }
7554  Utilities->CallLogPop(539);
7555 }
7556 
7557 // ---------------------------------------------------------------------------
7558 
7559 void TTrack::CheckGapMap(int Caller) // test
7560 {
7561  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7562  int Position1, Position2;
7563  TTrackElement TrackElement1, TrackElement2;
7564  TGapMapIterator GapMapPtr;
7565 
7566  if(!GapMap.empty())
7567  {
7568  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7569  {
7570  int HLoc1 = GapMapPtr->first.first;
7571  int VLoc1 = GapMapPtr->first.second;
7572  int HLoc2 = GapMapPtr->second.first;
7573  int VLoc2 = GapMapPtr->second.second;
7574  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7575  {
7576  throw Exception("Failed to find H & V for gap1, GapMap in error");
7577  }
7578  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7579  {
7580  throw Exception("Failed to find H & V for gap2, GapMap in error");
7581  }
7582  if(TrackElementAt(17, Position1).TrackType != GapJump)
7583  {
7584  throw Exception("Element at Pos1 not a gap, GapMap in error");
7585  }
7586  if(TrackElementAt(18, Position2).TrackType != GapJump)
7587  {
7588  throw Exception("Element at Pos2 not a gap, GapMap in error");
7589  }
7590  }
7591  }
7592  unsigned int GapCount = 0;
7593 
7594  for(unsigned int a = 0; a < TrackVector.size(); a++)
7595  {
7596  TTrackElement CheckElement = Track->TrackVector.at(a);
7597  if(CheckElement.TrackType == GapJump)
7598  {
7599  GapCount++;
7600  }
7601  }
7602  if((GapMap.size() * 2) != GapCount)
7603  {
7604  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7605  (AnsiString)Caller);
7606  }
7607  Utilities->CallLogPop(540);
7608 }
7609 
7610 // ---------------------------------------------------------------------------
7611 
7612 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7613 {
7614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7615  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7616  {
7617  if(TrackFinished)
7618  {
7619  throw Exception("Error - TrackFinished with erase element still present");
7620  }
7621  Utilities->CallLogPop(541);
7622  return; // erased element, can't set ID
7623  }
7624  AnsiString IDString;
7625 
7626  if(TrackElement.HLoc < 0)
7627  {
7628  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7629  }
7630  else
7631  {
7632  IDString = AnsiString(TrackElement.HLoc) + "-";
7633  }
7634  if(TrackElement.VLoc < 0)
7635  {
7636  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7637  }
7638  else
7639  {
7640  IDString += AnsiString(TrackElement.VLoc);
7641  }
7642  TrackElement.ElementID = IDString;
7643  Utilities->CallLogPop(542);
7644 }
7645 
7646 // ---------------------------------------------------------------------------
7647 
7648 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7649 {
7650 // e.g. "8-13", "00008-13", "N43-N127", etc
7651  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7652  int DelimPos;
7653 
7654  for(int x = 1; x < String.Length() + 1; x++)
7655  {
7656  if(String.IsDelimiter("-", x))
7657  {
7658  DelimPos = x;
7659  break;
7660  }
7661  if(x == String.Length())
7662  {
7663  if(GiveMessages)
7664  {
7665  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7666  }
7667  Utilities->CallLogPop(543);
7668  return(-1);
7669  }
7670  }
7671  if(DelimPos == 1)
7672  {
7673  if(GiveMessages)
7674  {
7675  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7676  }
7677  Utilities->CallLogPop(544);
7678  return(-1);
7679  }
7680  if(DelimPos == String.Length())
7681  {
7682  if(GiveMessages)
7683  {
7684  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7685  }
7686  Utilities->CallLogPop(545);
7687  return(-1);
7688  }
7689  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7690  {
7691  if(GiveMessages)
7692  {
7693  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7694  }
7695  Utilities->CallLogPop(1508);
7696  return(-1);
7697  }
7698  int HLoc, VLoc;
7699 
7700  if(String.SubString(1, 1) != "N")
7701  {
7702  for(int x = 1; x < DelimPos; x++)
7703  {
7704  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7705  {
7706  if(GiveMessages)
7707  {
7708  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7709  }
7710  Utilities->CallLogPop(546);
7711  return(-1);
7712  }
7713  }
7714  }
7715  if(String.SubString(1, 1) == "N")
7716  {
7717  for(int x = 2; x < DelimPos; x++)
7718  {
7719  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7720  {
7721  if(GiveMessages)
7722  {
7723  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7724  }
7725  Utilities->CallLogPop(763);
7726  return(-1);
7727  }
7728  }
7729  }
7730  if(String.SubString(1, 1) == "N")
7731  {
7732  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7733  }
7734  else
7735  {
7736  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7737  }
7738  if(String.SubString(DelimPos + 1, 1) != "N")
7739  {
7740  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7741  {
7742  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7743  {
7744  if(GiveMessages)
7745  {
7746  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7747  }
7748  Utilities->CallLogPop(547);
7749  return(-1);
7750  }
7751  }
7752  }
7753  if(String.SubString(DelimPos + 1, 1) == "N")
7754  {
7755  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7756  {
7757  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7758  {
7759  if(GiveMessages)
7760  {
7761  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7762  }
7763  Utilities->CallLogPop(764);
7764  return(-1);
7765  }
7766  }
7767  }
7768  if(String.SubString(DelimPos + 1, 1) == "N")
7769  {
7770  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7771  }
7772  else
7773  {
7774  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7775  }
7776  THVPair HVPair(HLoc, VLoc);
7777  TTrackMapIterator TrackMapPtr;
7778 
7779  TrackMapPtr = TrackMap.find(HVPair);
7780  if(TrackMapPtr == TrackMap.end())
7781  {
7782  if(GiveMessages)
7783  {
7784  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7785  }
7786  Utilities->CallLogPop(548);
7787  return(-1);
7788  }
7789  Utilities->CallLogPop(549);
7790  return(TrackMapPtr->second);
7791 }
7792 
7793 // ---------------------------------------------------------------------------
7794 
7795 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7796 /*
7797  True for linked properly at both ends
7798 */
7799 {
7800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7801  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7802  int HLoc = TrackElement.HLoc;
7803  int VLoc = TrackElement.VLoc;
7804 
7805  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7806  {
7807  Utilities->CallLogPop(1821);
7808  return(false);
7809  }
7810  if(TrackElement.SpeedTag == 129) // vertical footbridge
7811  {
7812  // check top connection
7813  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7814  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7815  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7816  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7817  {
7818  Utilities->CallLogPop(550);
7819  return(false);
7820  }
7821  // check bottom connection
7822  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7823  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7824  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7825  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7826  {
7827  Utilities->CallLogPop(551);
7828  return(false);
7829  }
7830  }
7831  if(TrackElement.SpeedTag == 145) // vertical underpass
7832  {
7833  // check top connection
7834  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7835  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7836  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7837  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7838  {
7839  Utilities->CallLogPop(2114);
7840  return(false);
7841  }
7842  // check bottom connection
7843  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7844  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7845  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7846  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7847  {
7848  Utilities->CallLogPop(2115);
7849  return(false);
7850  }
7851  }
7852  if(TrackElement.SpeedTag == 130) // hor footbridge
7853  {
7854  // check left connection
7855  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7856  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7857  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7858  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7859  {
7860  Utilities->CallLogPop(552);
7861  return(false);
7862  }
7863  // check right connection
7864  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7865  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7866  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7867  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7868  {
7869  Utilities->CallLogPop(553);
7870  return(false);
7871  }
7872  }
7873  if(TrackElement.SpeedTag == 146) // hor u'pass
7874  {
7875  // check left connection
7876  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7877  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7878  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7879  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7880  {
7881  Utilities->CallLogPop(2116);
7882  return(false);
7883  }
7884  // check right connection
7885  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7886  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7887  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7888  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7889  {
7890  Utilities->CallLogPop(2117);
7891  return(false);
7892  }
7893  }
7894  Utilities->CallLogPop(554);
7895  return(true);
7896 }
7897 
7898 // ---------------------------------------------------------------------------
7899 
7900 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7901 /*
7902  return true if the SpeedTag present in the map at H & V
7903 */
7904 {
7905  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7906  AnsiString(SpeedTag));
7907  if(InactiveTrack2MultiMap.empty())
7908  {
7909  Utilities->CallLogPop(555);
7910  return(false);
7911  }
7912  THVPair HVPair(HLoc, VLoc);
7914  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7915  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7916 
7917  if(HVRange.first == HVRange.second)
7918  {
7919  Utilities->CallLogPop(556);
7920  return(false);
7921  }
7922  else
7923  {
7924  HVIt1 = HVRange.first;
7925  }
7926  TTrackElement Temp1, Temp2; // test
7927 
7928  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7929  if(--HVRange.second != HVRange.first)
7930  {
7931  HVIt2 = HVRange.second;
7932  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7933  }
7934  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7935  HVIt2->second).SpeedTag == SpeedTag)))
7936  {
7937  Utilities->CallLogPop(557);
7938  return(true);
7939  }
7940  else
7941  {
7942  Utilities->CallLogPop(558);
7943  return(false);
7944  }
7945 }
7946 
7947 // ---------------------------------------------------------------------------
7948 
7949 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7950 /*
7951  return true if the SpeedTag present in the map at H & V
7952 */
7953 {
7954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7955  AnsiString(SpeedTag));
7956  if(TrackMap.empty())
7957  {
7958  Utilities->CallLogPop(559);
7959  return(false);
7960  }
7961  THVPair HVPair(HLoc, VLoc);
7962  TTrackMapIterator End = TrackMap.end();
7963  TTrackMapIterator It = End;
7964 
7965  It = TrackMap.find(HVPair);
7966  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7967  {
7968  Utilities->CallLogPop(560);
7969  return(true);
7970  }
7971  else
7972  {
7973  Utilities->CallLogPop(561);
7974  return(false);
7975  }
7976 }
7977 
7978 // ---------------------------------------------------------------------------
7979 
7980 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7981 {
7982 /*
7983  General:
7984  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7985  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7986  a NamedNonStationLocation.
7987  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7988  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7989  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7990  platform at that location).
7991 
7992  Linked named location elements are those explained in TTrack::TTrack()
7993 
7994  Detail:
7995  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7996  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7997  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7998  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7999  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8000  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8001 
8002  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8003  this function a single element should be in the List (normally from the user's selection but can also be from
8004  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8005  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8006  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8007  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8008  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8009  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8010  moves them into the Map. At the end all linked elements are in the Map.
8011 
8012  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8013  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8014  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8015 */
8016 
8017 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8018 // Display->FileDiagnostics(TestString);//test
8019 
8020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8021  AnsiString TestString1, TestString2; // test
8022 
8023  Track->LNDone2MultiMap.clear();
8024  if(LNPendingList.size() != 1)
8025  {
8026  throw Exception("LNPendingList size not 1 on entry");
8027  }
8028  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8029  while(!LNPendingList.empty())
8030  {
8031  CurrentElementNumber = LNPendingList.front();
8032  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8033  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
8034  int H = CurrentElement->HLoc;
8035  int V = CurrentElement->VLoc;
8036  int Tag = CurrentElement->SpeedTag;
8037  if(Tag == 76) // top plat
8038  {
8039  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8040  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8041  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8042  for(int x = 0; x < 25; x++)
8043  {
8044  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8045  {
8046  LNPendingList.insert(LNPendingList.end(), NewElement);
8047  }
8048  }
8049  }
8050  else if(Tag == 77) // bot plat
8051  {
8052  for(int x = 0; x < 25; x++)
8053  {
8054  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8055  {
8056  LNPendingList.insert(LNPendingList.end(), NewElement);
8057  }
8058  }
8059  }
8060  else if(Tag == 78) // l plat
8061  {
8062  for(int x = 0; x < 25; x++)
8063  {
8064  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8065  {
8066  LNPendingList.insert(LNPendingList.end(), NewElement);
8067  }
8068  }
8069  }
8070  else if(Tag == 79) // r plat
8071  {
8072  for(int x = 0; x < 25; x++)
8073  {
8074  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8075  {
8076  LNPendingList.insert(LNPendingList.end(), NewElement);
8077  }
8078  }
8079  }
8080  else if(Tag == 96) // conc
8081  {
8082  for(int x = 0; x < 28; x++)
8083  {
8084  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8085  {
8086  LNPendingList.insert(LNPendingList.end(), NewElement);
8087  }
8088  }
8089  }
8090  else if(Tag == 129) // vert footbridge
8091  {
8092  for(int x = 0; x < 8; x++)
8093  {
8094  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8095  {
8096  LNPendingList.insert(LNPendingList.end(), NewElement);
8097  }
8098  }
8099  }
8100  else if(Tag == 130) // hor footbridge
8101  {
8102  for(int x = 0; x < 8; x++)
8103  {
8104  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8105  {
8106  LNPendingList.insert(LNPendingList.end(), NewElement);
8107  }
8108  }
8109  }
8110  else if(Tag == 131) // named location
8111  {
8112  for(int x = 0; x < 4; x++)
8113  {
8114  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8115  {
8116  LNPendingList.insert(LNPendingList.end(), NewElement);
8117  }
8118  }
8119  }
8120  else if(Tag == 145) // v u'pass
8121  {
8122  for(int x = 0; x < 8; x++)
8123  {
8124  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8125  {
8126  LNPendingList.insert(LNPendingList.end(), NewElement);
8127  }
8128  }
8129  }
8130  else if(Tag == 146) // h u'pass
8131  {
8132  for(int x = 0; x < 8; x++)
8133  {
8134  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8135  {
8136  LNPendingList.insert(LNPendingList.end(), NewElement);
8137  }
8138  }
8139  }
8140  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8141 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8142  if(AddingElements)
8143  {
8144  int HPos, VPos; // not used but needed for FindText function
8145  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8146  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8147  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8148  {
8149  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8150  if((ExistingName != "") && (ExistingName != LocationName))
8151  {
8152  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8153  {
8154  } // name not in LocationNameMultiMap, so don't erase from TextVector
8155  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8156  {
8157  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8158  {
8159  ;
8160  } // condition not used
8161 
8162  }
8163  }
8164  }
8165  }
8166  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8167  // track at that loc
8168  THVPair HVPair(H, V);
8169  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8170  LNDone2MultiMapEntry.first = HVPair;
8171  LNDone2MultiMapEntry.second = LNPendingList.front();
8172  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8173  LNPendingList.erase(LNPendingList.begin());
8174  }
8175 
8176 // search all name multimap for same name where corresponding active elements don't appear in
8177 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8178 
8179  TLocationNameMultiMapIterator SNIterator;
8180  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8181  bool FoundFlag, ErasedFlag = false;
8182 
8183  if(SNRange.first != SNRange.second)
8184  {
8185  SNRange.first--; // now pointing to before the first
8186  SNRange.second--; // now pointing to the last
8187  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8188  {
8189  // Same elements are in Done map as in name map
8190  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8191  {
8192  ErasedFlag = true;
8193  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8194  TVIt->LocationName = "";
8195  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8196  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8197  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8198  {
8199  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8200  if(FoundFlag)
8201  {
8202  TrackElementAt(20, Position).LocationName = "";
8203  TrackElementAt(21, Position).ActiveTrackElementName = "";
8204  }
8205  }
8206  // erase name in name map
8207 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8208  }
8209  }
8210  }
8211  if(ErasedFlag)
8212  {
8214  }
8215  if(TrackFinished)
8216  {
8218  }
8219 // set here as well as in LinkTrack so don't have to link track just because a name added
8220 // if track not finished then will be set when track validated
8221 
8222 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8223 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8224 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8225 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8226 // so the error would be seen.
8227 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8228  std::pair<AnsiString, char>TempMapPair;
8229 
8230  ContinuationNameMap.clear();
8231  for(int x = 0; x < Track->TrackVectorSize(); x++)
8232  {
8233  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
8234  {
8235  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
8236  TempMapPair.second = 'x'; // unused
8237  ContinuationNameMap.insert(TempMapPair);
8238  }
8239  }
8240 //end of addition
8241  CheckLocationNameMultiMap(1); // test
8242  Utilities->CallLogPop(562);
8243 }
8244 
8245 // ---------------------------------------------------------------------------
8246 
8247 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8248 /*
8249  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8250  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8251 */
8252 {
8253  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8254  AnsiString(SpeedTag));
8255  if(!NamedLocationElementAt(2, HLoc, VLoc))
8256  {
8257  Utilities->CallLogPop(948);
8258  return(false);
8259  }
8260  bool FoundFlag;
8261  int Position = -1;
8262  TIMPair IMPair;
8263 
8264  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8265  {
8266  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8267  if(FoundFlag)
8268  {
8269  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8270  {
8271  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8272  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8273  // don't allow duplicates in either list, or processing takes a lot longer
8274  {
8275  FoundElement = MapPos;
8276  Utilities->CallLogPop(563);
8277  return(true);
8278  }
8279  }
8280  }
8281  }
8282  else
8283  {
8284  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8285  if(FoundFlag)
8286  {
8287  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8288  {
8289  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8290  {
8291  FoundElement = IMPair.first;
8292  Utilities->CallLogPop(564);
8293  return(true);
8294  }
8295  }
8296  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8297  {
8298  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8299  {
8300  FoundElement = IMPair.second;
8301  Utilities->CallLogPop(565);
8302  return(true);
8303  }
8304  }
8305  }
8306  }
8307  Utilities->CallLogPop(566);
8308  return(false);
8309 }
8310 
8311 // ---------------------------------------------------------------------------
8312 
8313 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8314 /*
8315  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8316  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8317  with the new name
8318 */
8319 {
8320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8321  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8322 
8323  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8324  int HLoc = TrackElement->HLoc;
8325  int VLoc = TrackElement->VLoc;
8326  bool FoundFlag;
8327 
8328  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8329  // only have timetable names for adjacent platforms & named locations
8330  {
8331  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8332  if(FoundFlag)
8333  {
8334  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8335  }
8336  }
8337  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8338 
8339  if(ErrorString != "")
8340  {
8341  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8342  }
8343  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8344  CheckLocationNameMultiMap(2); // test
8345  Utilities->CallLogPop(567);
8346 }
8347 
8348 // ---------------------------------------------------------------------------
8349 
8350 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8351 /*
8352  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8353 */
8354 {
8355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8356  if(LNDone2MultiMap.empty())
8357  {
8358  Utilities->CallLogPop(568);
8359  return(false);
8360  }
8361  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8362 
8363  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8364  {
8365  if(LNDone2MultiMapIterator->second == MapPos)
8366  {
8367  Utilities->CallLogPop(569);
8368  return(true);
8369  }
8370  }
8371  Utilities->CallLogPop(570);
8372  return(false);
8373 }
8374 
8375 // ---------------------------------------------------------------------------
8376 
8377 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8378 /*
8379  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8380 */
8381 {
8382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8383  if(LNPendingList.empty())
8384  {
8385  Utilities->CallLogPop(571);
8386  return(false);
8387  }
8388  TLNPendingListIterator LNPendingListIterator;
8389 
8390  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8391  {
8392  if(*LNPendingListIterator == MapPos)
8393  {
8394  Utilities->CallLogPop(572);
8395  return(true);
8396  }
8397  }
8398  Utilities->CallLogPop(573);
8399  return(false);
8400 }
8401 
8402 // ---------------------------------------------------------------------------
8403 
8404 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8405 /*
8406  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8407 */
8408 {
8409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8410  THVPair HVPair(HLoc, VLoc);
8411  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8412  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8413 
8414  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8415  {
8416  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8417  {
8418  Utilities->CallLogPop(574);
8419  return(true);
8420  }
8421  }
8422  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8423  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8424  {
8425  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8426  {
8427  Utilities->CallLogPop(575);
8428  return(true);
8429  }
8430  }
8431  Utilities->CallLogPop(576);
8432  return(false);
8433 }
8434 
8435 // ---------------------------------------------------------------------------
8436 
8437 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8438 {
8439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8440  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8441  {
8442  Utilities->CallLogPop(1953);
8443  return(true);
8444  }
8445  Utilities->CallLogPop(1954);
8446  return(false);
8447 }
8448 
8449 // ---------------------------------------------------------------------------
8450 
8451 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8452 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8453 //program and used when try to save as a .rly file
8454 {
8455  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8458  if(LocationNameMultiMap.empty()) //no names so no duplicates
8459  {
8460  Utilities->CallLogPop(2254);
8461  return(false);
8462  }
8463  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8464  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8465  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8466  {
8468  {
8469  if(GiveMessage)
8470  {
8471  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8472  }
8473  Utilities->CallLogPop(2255);
8474  return(true);
8475  }
8476  }
8477  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8478  {
8479  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8480  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8481  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8482  {
8484  {
8485  if(GiveMessage)
8486  {
8487  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8488  }
8489  Utilities->CallLogPop(2256);
8490  return(true);
8491  }
8492  }
8493  }
8494  Utilities->CallLogPop(2257);
8495  return(false); //OK, no duplicates
8496 }
8497 
8498 // ---------------------------------------------------------------------------
8499 
8501 {
8502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8503  THVPair HVPair;
8504  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8505  //for use in the duplicate check
8506  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8507  {
8508  if(LNMMIt->second < 0) //active track element
8509  {
8510  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8511  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8512  }
8513  else //inactive track element
8514  {
8515  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8516  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8517  }
8518  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8519  }
8520  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8521 
8522  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8523  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8524  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8525 
8526  std::list<THVPair> HVLinkedList;
8527 
8528  //set the first value to true and add it to the list
8529  HVPairsLinkedMap.begin()->second = true;
8530  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8531  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8532  //examination
8533  THVPair HVPairUnderExamination;
8534  THVPairsLinkedMap::iterator HVPLMIt;
8535  THVPair HVPairNew;
8536  while(!HVLinkedList.empty())
8537  {
8538  HVPairUnderExamination = HVLinkedList.front();
8539  HVLinkedList.pop_front();
8540  HVPairNew.first = HVPairUnderExamination.first;
8541  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8542  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8543  if(HVPLMIt != HVPairsLinkedMap.end())
8544  {
8545  if(!HVPLMIt->second)
8546  {
8547  HVLinkedList.push_back(HVPLMIt->first);
8548  }
8549  HVPLMIt->second = true;
8550  }
8551  HVPairNew.first = HVPairUnderExamination.first - 1;
8552  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8553  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8554  if(HVPLMIt != HVPairsLinkedMap.end())
8555  {
8556  if(!HVPLMIt->second)
8557  {
8558  HVLinkedList.push_back(HVPLMIt->first);
8559  }
8560  HVPLMIt->second = true;
8561  }
8562  HVPairNew.first = HVPairUnderExamination.first;
8563  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8564  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8565  if(HVPLMIt != HVPairsLinkedMap.end())
8566  {
8567  if(!HVPLMIt->second)
8568  {
8569  HVLinkedList.push_back(HVPLMIt->first);
8570  }
8571  HVPLMIt->second = true;
8572  }
8573  HVPairNew.first = HVPairUnderExamination.first + 1;
8574  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8575  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8576  if(HVPLMIt != HVPairsLinkedMap.end())
8577  {
8578  if(!HVPLMIt->second)
8579  {
8580  HVLinkedList.push_back(HVPLMIt->first);
8581  }
8582  HVPLMIt->second = true;
8583  }
8584  }
8585 
8586  //at the end if any have a false bool then the name is duplicated so return false
8587  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8588  {
8589  if(!HVPLMIt->second)
8590  {
8591  Utilities->CallLogPop(2258);
8592  return(false);
8593  }
8594  }
8595  Utilities->CallLogPop(2259);
8596  return(true);
8597 }
8598 
8599 // ---------------------------------------------------------------------------
8600 
8601 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8602 /*
8603  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8604 */
8605 
8606 {
8607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8608  if(LocationName == "")
8609  {
8610  Utilities->CallLogPop(577);
8611  return(false);
8612  }
8613 // new for v0.2b
8614 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8616  {
8617  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8618  ActiveTrackElementNameMap.clear();
8619  for(unsigned int x = 0; x < TrackVector.size(); x++)
8620  {
8621  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
8622  == ContinuationNameMap.end())
8623  {
8624  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8625  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
8626  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8627  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8628  }
8629  }
8631  }
8632  Utilities->CallLogPop(578);
8633  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8634 // end of new section
8635 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8636 }
8637 
8638 // ---------------------------------------------------------------------------
8639 
8640 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8641 /*
8642  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8643  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8644  new names in the vectors.
8645 */
8646 {
8647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8648  bool FoundFlag, ErasedFlag = false;
8649  TLocationNameMultiMapIterator SNIterator;
8650  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8651 
8652  if(SNRange.first != SNRange.second)
8653  {
8654  ErasedFlag = true;
8655  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8656  {
8657  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8658  TVIt->LocationName = "";
8659  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8660  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8661  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8662  {
8663  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8664  if(FoundFlag)
8665  {
8666  TrackElementAt(25, Position).LocationName = "";
8667  TrackElementAt(26, Position).ActiveTrackElementName = "";
8668  }
8669  }
8670  }
8671  }
8672  if(ErasedFlag)
8673  {
8675  }
8676  CheckLocationNameMultiMap(3); // test
8677  Utilities->CallLogPop(579);
8678 }
8679 
8680 // ---------------------------------------------------------------------------
8681 
8682 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8683 /*
8684  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8685  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8686  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8687  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8688  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8689  naming up to date with the deletion or insertion.
8690 */
8691 {
8692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8693  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8694  LNPendingList.clear();
8695  AnsiString LocationName;
8696  int MapPos;
8697  bool FoundFlag = 0;
8698 
8699 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8700  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8701  if(FoundFlag)
8702  {
8703  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8704  if(LocationName != "")
8705  {
8706  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8707  EnterLocationName(13, LocationName, true);
8708  Utilities->CallLogPop(2251);
8709  return;
8710  }
8711  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8712  if(LocationName != "")
8713  {
8714  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8715  EnterLocationName(14, LocationName, true);
8716  Utilities->CallLogPop(2252);
8717  return;
8718  }
8719  }
8720 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8721 
8722  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8723  if(FoundFlag)
8724  {
8725  LocationName = TrackElementAt(1004, Position).LocationName;
8726  if(LocationName != "")
8727  {
8728  int ModifiedPosition = -1 - Position;
8729  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8730  EnterLocationName(15, LocationName, true);
8731  Utilities->CallLogPop(2253);
8732  return;
8733  }
8734  }
8735  if(SpeedTag == 76) // top plat
8736  {
8737  for(int x = 0; x < 25; x++)
8738  {
8739  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8740  {
8741  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8742  EnterLocationName(3, LocationName, true);
8743  break;
8744  }
8745  }
8746  }
8747  else if(SpeedTag == 77) // bot plat
8748  {
8749  for(int x = 0; x < 25; x++)
8750  {
8751  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8752  {
8753  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8754  EnterLocationName(4, LocationName, true);
8755  break;
8756  }
8757  }
8758  }
8759  else if(SpeedTag == 78) // l plat
8760  {
8761  for(int x = 0; x < 25; x++)
8762  {
8763  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8764  {
8765  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8766  EnterLocationName(5, LocationName, true);
8767  break;
8768  }
8769  }
8770  }
8771  else if(SpeedTag == 79) // r plat
8772  {
8773  for(int x = 0; x < 25; x++)
8774  {
8775  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8776  {
8777  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8778  EnterLocationName(6, LocationName, true);
8779  break;
8780  }
8781  }
8782  }
8783  else if(SpeedTag == 96) // conc
8784  {
8785  for(int x = 0; x < 28; x++)
8786  {
8787  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8788  {
8789  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8790  EnterLocationName(7, LocationName, true);
8791  break;
8792  }
8793  }
8794  }
8795  else if(SpeedTag == 129) // vert footbridge
8796  {
8797  for(int x = 0; x < 8; x++)
8798  {
8799  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8800  {
8801  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8802  EnterLocationName(8, LocationName, true);
8803  break;
8804  }
8805  }
8806  }
8807  else if(SpeedTag == 130) // hor footbridge
8808  {
8809  for(int x = 0; x < 8; x++)
8810  {
8811  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8812  {
8813  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8814  EnterLocationName(9, LocationName, true);
8815  break;
8816  }
8817  }
8818  }
8819  else if(SpeedTag == 145) // vert u'pass
8820  {
8821  for(int x = 0; x < 8; x++)
8822  {
8823  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8824  {
8825  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8826  EnterLocationName(11, LocationName, true);
8827  break;
8828  }
8829  }
8830  }
8831  else if(SpeedTag == 146) // hor u'pass
8832  {
8833  for(int x = 0; x < 8; x++)
8834  {
8835  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8836  {
8837  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8838  EnterLocationName(12, LocationName, true);
8839  break;
8840  }
8841  }
8842  }
8843  else if(SpeedTag == 131) // named location
8844  {
8845  for(int x = 0; x < 4; x++)
8846  {
8847  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8848  {
8849  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8850  EnterLocationName(10, LocationName, true);
8851  break;
8852  }
8853  }
8854  }
8855 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8856  Utilities->CallLogPop(580);
8857 }
8858 
8859 // ---------------------------------------------------------------------------
8860 
8861 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8862 /*
8863  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8864  true if a LocationName is found, and also returns the name and the adjusted vector position.
8865 */
8866 {
8867  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8868  AnsiString(SpeedTag));
8869  bool FoundFlag;
8870  TIMPair IMPair;
8871  TTrackVectorIterator TempElement;
8872  int Position;
8873 
8874  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8875  if(FoundFlag)
8876  {
8877  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8878  {
8879  TempElement = InactiveTrackVector.begin() + IMPair.first;
8880  if(TempElement->LocationName != "")
8881  {
8882  LocationName = TempElement->LocationName;
8883  FoundElement = IMPair.first;
8884  Utilities->CallLogPop(581);
8885  return(true);
8886  }
8887  }
8888  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8889  {
8890  TempElement = InactiveTrackVector.begin() + IMPair.second;
8891  if(TempElement->LocationName != "")
8892  {
8893  LocationName = TempElement->LocationName;
8894  FoundElement = IMPair.second;
8895  Utilities->CallLogPop(582);
8896  return(true);
8897  }
8898  }
8899  }
8900  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8901  if(FoundFlag)
8902  {
8903  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8904  {
8905  TempElement = TrackVector.begin() + Position;
8906  if(TempElement->LocationName != "")
8907  {
8908  LocationName = TempElement->LocationName;
8909  FoundElement = -1 - Position;
8910  Utilities->CallLogPop(583);
8911  return(true);
8912  }
8913  }
8914  }
8915  Utilities->CallLogPop(584);
8916  return(false);
8917 }
8918 
8919 // ---------------------------------------------------------------------------
8920 
8921 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8922 {
8923 // check quantity in map & vectors match
8924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8925  unsigned int Count = 0;
8926 
8927  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8928  {
8929  Utilities->CallLogPop(2059);
8930  return;
8931  }
8932  AnsiString SName, TName, ErrorString;
8933 
8934  for(unsigned int x = 0; x < TrackVector.size(); x++)
8935  {
8936  if(TrackVector.at(x).FixedNamedLocationElement)
8937  {
8938  if(TrackVector.at(x).TrackType != FootCrossing)
8939  {
8940  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8941  AnsiString(Caller));
8942  }
8943  Count++;
8944  }
8945  }
8946  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8947  {
8948  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8949  {
8950  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
8951  (InactiveTrackVector.at(x).TrackType != Concourse))
8952  {
8953  throw Exception
8954  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8955  AnsiString(Caller));
8956  }
8957  Count++;
8958  }
8959  }
8960  if(LocationNameMultiMap.size() != Count)
8961  {
8962  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8963  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8964  }
8965 // check all entries in both vectors match entries in name multimap
8967 
8968  for(unsigned int x = 0; x < TrackVector.size(); x++)
8969  {
8970  if(TrackVector.at(x).FixedNamedLocationElement)
8971  {
8972  SName = TrackVector.at(x).LocationName;
8973  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8974  if(ErrorString != "")
8975  {
8976  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8977  }
8978  if(SNIt->second != -1 - (int)x)
8979  {
8980  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8981  AnsiString(Caller));
8982  }
8983  }
8984  // check corresponding platform for all Timetable entries that aren't empty
8985  TName = TrackVector.at(x).ActiveTrackElementName;
8986  TIMPair IMPair;
8987  bool FoundFlag = false;
8988  if(TName != "")
8989  {
8990  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
8991  if(FoundFlag)
8992  {
8993  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8995  {
8996  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8997  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8998  }
8999  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9000  {
9001  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
9002  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9003  AnsiString(Caller));
9004  }
9005  }
9006  else
9007  {
9008  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
9009  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9010  }
9011  }
9012  }
9013  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9014  {
9015  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
9016  {
9017  SName = InactiveTrackVector.at(x).LocationName;
9018  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9019  if(ErrorString != "")
9020  {
9021  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9022  }
9023  if(SNIt->second != (int)x)
9024  {
9025  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9026  AnsiString(Caller));
9027  }
9028  }
9029  }
9030  Utilities->CallLogPop(585);
9031 }
9032 
9033 // ---------------------------------------------------------------------------
9034 
9036  AnsiString &ErrorString)
9037 {
9038 /*
9039  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9040  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9041  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9042 */
9043  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9044  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9045  ErrorString = "";
9046  bool FoundFlag = false;
9047  TLocationNameMultiMapIterator SNIterator;
9048  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9049 
9050  if(SNRange.first == SNRange.second)
9051  {
9052  ErrorString = "Error, Name " + LocationName + " not found in map";
9053  Utilities->CallLogPop(586);
9054  return(SNRange.first);
9055  }
9056  else
9057  {
9058  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9059  {
9060  if(SNIterator->second < 0)
9061  {
9062  int TVPos = -1 - SNIterator->second;
9063  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9064  if(TVIt == TrackElement)
9065  {
9066  FoundFlag = true;
9067  Utilities->CallLogPop(587);
9068  return(SNIterator);
9069  }
9070  }
9071  else
9072  {
9073  int ITVPos = SNIterator->second;
9074  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9075  if(ITVIt == TrackElement)
9076  {
9077  FoundFlag = true;
9078  Utilities->CallLogPop(588);
9079  return(SNIterator);
9080  }
9081  }
9082  }
9083  }
9084  if(!FoundFlag)
9085  {
9086  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9087  }
9088  Utilities->CallLogPop(589);
9089  return(SNIterator);
9090 }
9091 
9092 // ---------------------------------------------------------------------------
9093 
9094 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9095 {
9096 /*
9097  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9098  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9099 */
9100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9101  TLocationNameMultiMapEntry LocationNameEntry;
9102 
9103  LocationNameEntry.first = NewName;
9104  LocationNameEntry.second = SNIterator->second;
9105  LocationNameMultiMap.erase(SNIterator);
9106  LocationNameMultiMap.insert(LocationNameEntry);
9107  Utilities->CallLogPop(590);
9108 }
9109 
9110 // ---------------------------------------------------------------------------
9111 
9113 {
9114 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9115  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9116  if(Position < 0) // footcrossing
9117  {
9118  int TruePos = -1 - Position;
9119  // new check at v0.2b
9120  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9121  {
9122  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9123  }
9124  Utilities->CallLogPop(591);
9125  return (TrackVector.begin() + TruePos);
9126  }
9127  else
9128  {
9129  // new check at v0.2b
9130  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9131  {
9132  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9133  }
9134  Utilities->CallLogPop(592);
9135  return (InactiveTrackVector.begin() + Position);
9136  }
9137 }
9138 
9139 // ---------------------------------------------------------------------------
9140 
9141 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9142 {
9143 /*
9144  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9145  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9146  LocationNameMultiMap.
9147 */
9148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9149  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9150  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9151 
9152  if(!InactiveTrack2MultiMap.empty())
9153  {
9154  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9155  InactiveTrack2MultiMapIterator++)
9156  {
9157  if(InactiveTrack2MultiMapIterator->second > VecPos)
9158  {
9159  InactiveTrack2MultiMapIterator->second--;
9160  }
9161  // can't be == VecPos as that position erased
9162  }
9163  }
9164  if(!LocationNameMultiMap.empty())
9165  {
9166  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9167  LocationNameMultiMapIterator++)
9168  {
9169  if(LocationNameMultiMapIterator->second < 0)
9170  {
9171  continue; // deal with TrackVectors separately
9172  }
9173  if(LocationNameMultiMapIterator->second > (int)VecPos)
9174  {
9175  LocationNameMultiMapIterator->second--;
9176  }
9177  }
9178  }
9179  Utilities->CallLogPop(593);
9180 }
9181 
9182 // ---------------------------------------------------------------------------
9183 
9184 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9185 {
9186 /*
9187  After an element has been erased from the track vector, all the later elements are moved down one. This function
9188  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9189  LocationNameMultiMap.
9190 */
9191  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9192  TTrackMapIterator TrackMapIterator;
9193  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9194 
9195  if(!TrackMap.empty())
9196  {
9197  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9198  {
9199  if(TrackMapIterator->second > VecPos)
9200  {
9201  TrackMapIterator->second--;
9202  }
9203  // can't be == VecPos as that position erased
9204  }
9205  }
9206  if(!LocationNameMultiMap.empty())
9207  {
9208  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9209  LocationNameMultiMapIterator++)
9210  {
9211  if(LocationNameMultiMapIterator->second >= 0)
9212  {
9213  continue; // deal with InactiveTrackVectors separately
9214  }
9215  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9216  // Val -1 -2 -3 -4 -5 -6 -7 -8
9217  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9218  {
9219  LocationNameMultiMapIterator->second++;
9220  }
9221  }
9222  }
9223  for(unsigned int x = 0; x < TrackVector.size(); x++)
9224  {
9225  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
9226  if(TkEl.TrackType == GapJump)
9227  {
9228  // position 0 is the gap
9229  if(TkEl.Conn[0] == int(VecPos))
9230  {
9231  TkEl.Conn[0] = -1; // connected to a deleted gap
9232  continue;
9233  }
9234  if(TkEl.Conn[0] > int(VecPos))
9235  {
9236  TkEl.Conn[0]--;
9237  }
9238  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9239  {
9240  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9241  {
9242  TkEl.Conn[0] = -1;
9243  }
9244  }
9245  }
9246  }
9247  Utilities->CallLogPop(1433);
9248 }
9249 
9250 // ---------------------------------------------------------------------------
9251 
9253 /*
9254  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9255  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9256  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9257 */
9258 {
9259  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9260  LocationNameMultiMap.clear();
9261  TLocationNameMultiMapEntry LocationNameEntry;
9262  TTrackElement TrackElement;
9263 
9264  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9265  {
9266  TrackElement = TrackVector.at(TVPos);
9267  if(TrackElement.FixedNamedLocationElement)
9268  {
9269  LocationNameEntry.first = TrackElement.LocationName;
9270  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9271  LocationNameMultiMap.insert(LocationNameEntry);
9272  }
9273  }
9274 
9275  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9276  {
9277  TrackElement = InactiveTrackVector.at(ITVPos);
9278  if(TrackElement.FixedNamedLocationElement)
9279  {
9280  LocationNameEntry.first = TrackElement.LocationName;
9281  LocationNameEntry.second = ITVPos;
9282  LocationNameMultiMap.insert(LocationNameEntry);
9283  }
9284  }
9285  Utilities->CallLogPop(594);
9286 }
9287 
9288 // ---------------------------------------------------------------------------
9289 
9291 // Return true if there is a named location present in the railway
9292 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9293 {
9294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9295  TTrackVectorIterator ITVI;
9296 
9297  if(InactiveTrackVector.empty())
9298  {
9299  Utilities->CallLogPop(1343);
9300  return(false);
9301  }
9302  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9303  {
9304  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9305  {
9306  Utilities->CallLogPop(1404);
9307  return(true);
9308  }
9309  }
9310  Utilities->CallLogPop(1344);
9311  return(false);
9312 }
9313 
9314 // ---------------------------------------------------------------------------
9315 
9317 /*
9318  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9319 */
9320 {
9321  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9322 // ResetDistanceElements(6);
9323  for(unsigned int x = 0; x < TrackVector.size(); x++)
9324  {
9325  TTrackElement &TE = TrackElementAt(718, x);
9328  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9329  {
9332  }
9333  }
9334 /* old function
9335  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
9336  {
9337  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
9338  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
9339  }
9340  else
9341  {
9342  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
9343  }
9344  }
9345 */
9346  Utilities->CallLogPop(617);
9347 }
9348 
9349 // ---------------------------------------------------------------------------
9350 
9351 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9352 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9353 {
9354  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9355  for(unsigned int x = 0; x < TrackVector.size(); x++)
9356  {
9357  TTrackElement TempElement = TrackVector.at(x);
9358  if(TempElement.Length01 > -1)
9359  {
9360  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9361  }
9362  if(TempElement.Length23 > -1)
9363  {
9364  MarkOneLength(2, TempElement, false, Disp);
9365  }
9366  }
9367  Disp->Update();
9368  Utilities->CallLogPop(618);
9369 }
9370 
9371 // ---------------------------------------------------------------------------
9372 
9373 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9374 /*
9375  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
9376  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9377  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9378  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9379  track as indicated by FirstTrack (true for track01 & false for track23).
9380 */
9381 {
9382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9383  AnsiString((short)FirstTrack));
9384  bool LengthDifferent = false, SpeedDifferent = false;
9385 
9386  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9387  {
9388  Utilities->CallLogPop(619);
9389  return;
9390  }
9391  int EXArray[16][2] =
9392  {{4, 6}, {2, 8}, // horizontal & vertical
9393  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9394  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9395  {1, 9}, {3, 7}}; // forward & reverse diagonals
9396 
9397  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9398  Graphics::TBitmap *Bitmap;
9399 
9400  if(FirstTrack)
9401  {
9402  InLink = TrackElement.Link[0];
9403  OutLink = TrackElement.Link[1];
9404  }
9405  else
9406  {
9407  InLink = TrackElement.Link[2];
9408  OutLink = TrackElement.Link[3];
9409  }
9410  for(int x = 0; x < 16; x++)
9411  {
9412  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9413  {
9414  Index = x;
9415  }
9416  }
9417  if(Index == -1)
9418  {
9419  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9420  }
9421 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9422  the graphic for each of which is different because of the shape of the overbridge. The basic
9423  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9424  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9425  int BrEXArray[24][2] = {
9426  {4,6},{2,8},{1,9},{3,7},
9427  {1,9},{3,7},{1,9},{3,7},
9428  {2,8},{4,6},{2,8},{4,6}
9429 */
9430  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9431  {
9432  if(Index == 1)
9433  {
9434  if(TrackElement.SpeedTag == 49)
9435  {
9436  BrNum = 1 + 16;
9437  }
9438  else if(TrackElement.SpeedTag == 54)
9439  {
9440  BrNum = 8 + 16;
9441  }
9442  else if(TrackElement.SpeedTag == 55)
9443  {
9444  BrNum = 10 + 16;
9445  }
9446  }
9447  else if(Index == 0)
9448  {
9449  if(TrackElement.SpeedTag == 48)
9450  {
9451  BrNum = 0 + 16;
9452  }
9453  else if(TrackElement.SpeedTag == 58)
9454  {
9455  BrNum = 11 + 16;
9456  }
9457  else if(TrackElement.SpeedTag == 59)
9458  {
9459  BrNum = 9 + 16;
9460  }
9461  }
9462  else if(Index == 14)
9463  {
9464  if(TrackElement.SpeedTag == 50)
9465  {
9466  BrNum = 2 + 16;
9467  }
9468  else if(TrackElement.SpeedTag == 52)
9469  {
9470  BrNum = 4 + 16;
9471  }
9472  else if(TrackElement.SpeedTag == 57)
9473  {
9474  BrNum = 6 + 16;
9475  }
9476  }
9477  else if(Index == 15)
9478  {
9479  if(TrackElement.SpeedTag == 51)
9480  {
9481  BrNum = 3 + 16;
9482  }
9483  else if(TrackElement.SpeedTag == 53)
9484  {
9485  BrNum = 7 + 16;
9486  }
9487  else if(TrackElement.SpeedTag == 56)
9488  {
9489  BrNum = 5 + 16;
9490  }
9491  }
9492  }
9493  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9494  {
9495  GrNum = BrNum;
9496  }
9497  else
9498  {
9499  GrNum = Index;
9500  }
9501  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9502  {
9503  if(GrNum > 15) // underbridge
9504  {
9505  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9506  }
9507  else
9508  {
9509  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9510  }
9511  if(TrackElement.SpeedTag == 64)
9512  {
9513  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9514  }
9515  if(TrackElement.SpeedTag == 65)
9516  {
9518  }
9519  if(TrackElement.SpeedTag == 66)
9520  {
9522  }
9523  if(TrackElement.SpeedTag == 67)
9524  {
9526  }
9527  if(TrackElement.SpeedTag == 80)
9528  {
9529  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9530  }
9531  if(TrackElement.SpeedTag == 81)
9532  {
9534  }
9535  if(TrackElement.SpeedTag == 82)
9536  {
9538  }
9539  if(TrackElement.SpeedTag == 83)
9540  {
9542  }
9543  if(TrackElement.SpeedTag == 84)
9544  {
9546  }
9547  if(TrackElement.SpeedTag == 85)
9548  {
9550  }
9551  if(TrackElement.SpeedTag == 86)
9552  {
9554  }
9555  if(TrackElement.SpeedTag == 87)
9556  {
9558  }
9559  if(TrackElement.SpeedTag == 129)
9560  {
9561  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9562  }
9563  if(TrackElement.SpeedTag == 130)
9564  {
9566  }
9567  }
9568 
9569  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9570  {
9571  if(GrNum > 15) // underbridge
9572  {
9573  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9574  }
9575  else
9576  {
9577  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9578  }
9579  if(TrackElement.SpeedTag == 64)
9580  {
9581  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9582  }
9583  if(TrackElement.SpeedTag == 65)
9584  {
9585  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9586  }
9587  if(TrackElement.SpeedTag == 66)
9588  {
9589  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9590  }
9591  if(TrackElement.SpeedTag == 67)
9592  {
9593  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9594  }
9595  if(TrackElement.SpeedTag == 80)
9596  {
9597  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9598  }
9599  if(TrackElement.SpeedTag == 81)
9600  {
9601  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9602  }
9603  if(TrackElement.SpeedTag == 82)
9604  {
9605  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9606  }
9607  if(TrackElement.SpeedTag == 83)
9608  {
9609  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9610  }
9611  if(TrackElement.SpeedTag == 84)
9612  {
9613  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9614  }
9615  if(TrackElement.SpeedTag == 85)
9616  {
9617  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9618  }
9619  if(TrackElement.SpeedTag == 86)
9620  {
9621  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9622  }
9623  if(TrackElement.SpeedTag == 87)
9624  {
9625  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9626  }
9627  if(TrackElement.SpeedTag == 129)
9628  {
9629  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9630  }
9631  if(TrackElement.SpeedTag == 130)
9632  {
9633  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9634  }
9635  }
9636 
9637  else // SpeedDifferent only: red - use non sig graphics
9638  {
9639  if(GrNum > 15) // underbridge
9640  {
9641  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9642  }
9643  else
9644  {
9645  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9646  }
9647  if(TrackElement.SpeedTag == 64)
9648  {
9649  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9650  }
9651  if(TrackElement.SpeedTag == 65)
9652  {
9654  }
9655  if(TrackElement.SpeedTag == 66)
9656  {
9658  }
9659  if(TrackElement.SpeedTag == 67)
9660  {
9662  }
9663  if(TrackElement.SpeedTag == 80)
9664  {
9665  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9666  }
9667  if(TrackElement.SpeedTag == 81)
9668  {
9670  }
9671  if(TrackElement.SpeedTag == 82)
9672  {
9674  }
9675  if(TrackElement.SpeedTag == 83)
9676  {
9678  }
9679  if(TrackElement.SpeedTag == 84)
9680  {
9682  }
9683  if(TrackElement.SpeedTag == 85)
9684  {
9686  }
9687  if(TrackElement.SpeedTag == 86)
9688  {
9690  }
9691  if(TrackElement.SpeedTag == 87)
9692  {
9694  }
9695  if(TrackElement.SpeedTag == 129)
9696  {
9697  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9698  }
9699  if(TrackElement.SpeedTag == 130)
9700  {
9702  }
9703  }
9704  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9705  Utilities->CallLogPop(620);
9706 }
9707 
9708 // ---------------------------------------------------------------------------
9709 
9710 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9711 /* FirstTrack = LinkPos's 0 & 1
9712  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9713 */
9714 {
9715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9716  AnsiString((short)FirstTrack));
9717  LengthDifferent = false;
9718  SpeedDifferent = false;
9719  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9720  {
9721  if(TrackElement.Length01 != DefaultTrackLength)
9722  {
9723  LengthDifferent = true;
9724  }
9725  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9726  {
9727  SpeedDifferent = true;
9728  }
9729  if(LengthDifferent || SpeedDifferent)
9730  {
9731  Utilities->CallLogPop(625);
9732  return(false);
9733  }
9734  Utilities->CallLogPop(626);
9735  return(true);
9736  }
9737 
9738  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9739  {
9740  if(TrackElement.Length23 != DefaultTrackLength)
9741  {
9742  LengthDifferent = true;
9743  }
9744  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9745  {
9746  SpeedDifferent = true;
9747  }
9748  if(LengthDifferent || SpeedDifferent)
9749  {
9750  Utilities->CallLogPop(627);
9751  return(false);
9752  }
9753  Utilities->CallLogPop(628);
9754  return(true);
9755  }
9756 
9757  else // any other 1 track element, including platforms being present
9758  {
9759  if(TrackElement.Length01 != DefaultTrackLength)
9760  {
9761  LengthDifferent = true;
9762  }
9763  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9764  {
9765  SpeedDifferent = true;
9766  }
9767  if(LengthDifferent || SpeedDifferent)
9768  {
9769  Utilities->CallLogPop(629);
9770  return(false);
9771  }
9772  Utilities->CallLogPop(630);
9773  return(true);
9774  }
9775 }
9776 
9777 // ---------------------------------------------------------------------------
9778 
9779 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9780 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9781 {
9782  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9783  AnsiString(VLoc));
9784  bool FoundFlag;
9785  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9786 
9787  if(!FoundFlag)
9788  {
9789  Utilities->CallLogPop(633);
9790  return(false);
9791  }
9792  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9793  {
9794  Utilities->CallLogPop(634);
9795  return(true); // only need to check first since if second is a platform the the first must be too
9796  }
9797  else
9798  {
9799  Utilities->CallLogPop(635);
9800  return(false);
9801  }
9802 }
9803 
9804 // ---------------------------------------------------------------------------
9805 
9806 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9807 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9808 {
9809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9810  AnsiString(VLoc));
9811  bool FoundFlag;
9812  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9813 
9814  if(!FoundFlag)
9815  {
9816  Utilities->CallLogPop(636);
9817  return(false);
9818  }
9820  {
9821  Utilities->CallLogPop(637);
9822  return(true); // only need to check first since only one used for NamedNonStationLocations
9823  }
9824  else
9825  {
9826  Utilities->CallLogPop(638);
9827  return(false);
9828  }
9829 }
9830 
9831 // ---------------------------------------------------------------------------
9832 
9834 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9835  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9836  the front of train stop points for each direction.
9837  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9838  end (unless buffers at one or both ends in which case stop points are the end elements).
9839  Note that for a single element the stop point is the element itself (formula doesn't apply).
9840  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9841  repeating the procedure for every element. At the end all unused values are returned to -1.
9842  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9843 */
9844 {
9845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9846  TTrackElement TempElement, StartElement;
9847  AnsiString TempName;
9848  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9849  bool ForwardSet, ReverseSet;
9850 
9851  for(unsigned int x = 0; x < TrackVector.size(); x++)
9852  {
9853  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9854  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9855  }
9856  for(unsigned int x = 0; x < TrackVector.size(); x++)
9857  {
9858  ForwardSet = false;
9859  ReverseSet = false;
9860  TempElement = TrackVector.at(x);
9861  VecPos = x;
9862  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9863  // 2nd condition incl so don't re-examine elements with stop links set to 5
9864  {
9865  TempName = TempElement.ActiveTrackElementName;
9866  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9867  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9868  // an element linked at both ends where both links are also named elements
9869  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9870  {
9871  continue; // looking for an end element so skip this one
9872  }
9873  else // reached one end
9874  {
9875  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9876  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9877  // single named element linked at both ends
9878  {
9879  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9880  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9881  continue;
9882  }
9883  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9884  // single named buffer element (LinkPos 1 is the non-buffer end)
9885  {
9886  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9887  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9888  continue;
9889  }
9890  else
9891  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9892  // and platforms always on straight (conns 0 & 1) section of points
9893  {
9894  for(int y = 0; y < 2; y++)
9895  {
9896  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9897  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9898 /* TTrackElement Temp1 = TempElement;
9899  ***********New section, compiles but not checked - does bit below need to be else if?
9900  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9901  {
9902  //search along Dir direction until find other end, skip if Dir facing buffer end
9903  int NewDir = Dir;
9904  int NewVecPos;
9905  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9906  {
9907  NewVecPos = Temp1.Conn[NewDir];
9908  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9909  Temp1 = TrackElementAt(601, NewVecPos);
9910  }
9911  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9912  {
9913  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9914  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9915  }
9916  }
9917  ***************
9918 */
9919  // end may be linked at both ends but only one link named, or buffer with linked element named
9920  // if a buffer then the named linkpos has to be 1
9921  // already dealt with all types of single element so at least 2 linked named element
9922  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9923  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
9924  {
9925  StartElement = TempElement;
9926  StartVecPos = VecPos;
9927  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9928  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9929  EntryPos = 1 - Dir;
9930  StartEntryPos = 1 - Dir;
9931  Count = 1;
9932  // work along named elements until find the other end
9933  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9934  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9935  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9936  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9937  // all stop link pos's are set to 5
9938  {
9939  VecPos = TempElement.Conn[1 - EntryPos];
9940  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9941  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9942  EntryPos = TempEntryPos;
9943  Count++;
9944  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9945  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9946  }
9947  // here when reached other end, maybe buffers, continuation or last named linked element
9948  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9949  // terminal station, set end elements as stop elements
9950  {
9951  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9952  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9953  continue;
9954  }
9955  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9956  // terminal station, set end elements as stop elements
9957  {
9958  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9959  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9960  continue;
9961  }
9962  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9963  // NonStationLocation so set end elements as stop elements
9964  {
9965  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9966  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9967  continue;
9968  }
9969  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9970  ForwardNumber = ((Count + 1) / 2) + 1;
9971  ReverseNumber = (Count - ForwardNumber) + 1;
9972  Count = 1; // starting value
9973  EntryPos = 1 - Dir;
9974  TempElement = StartElement;
9975  VecPos = StartVecPos;
9976  if(Count == ForwardNumber)
9977  {
9978  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9979  ForwardSet = true;
9980  }
9981  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9982  {
9983  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9984  ReverseSet = true;
9985  }
9986  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9987  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9988  {
9989  VecPos = TempElement.Conn[1 - EntryPos];
9990  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9991  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9992  EntryPos = TempEntryPos;
9993  Count++;
9994  if(Count == ForwardNumber)
9995  {
9996  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9997  ForwardSet = true;
9998  }
9999  if(Count == ReverseNumber)
10000  {
10001  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10002  ReverseSet = true;
10003  }
10004  }
10005  }
10006  }
10007  }
10008  }
10009  }
10010  }
10011  for(unsigned int x = 0; x < TrackVector.size(); x++)
10012  {
10013  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
10014  {
10015  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
10016  }
10017  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
10018  {
10019  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
10020  }
10021  }
10022  Utilities->CallLogPop(639);
10023 }
10024 
10025 // ---------------------------------------------------------------------------
10026 
10027 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10028 {
10029  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10030  TTrackElement Next;
10031 
10033  while(ReturnNextInactiveTrackElement(1, Next))
10034  {
10035  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10036  {
10037  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10038  // need striped graphics
10039  {
10040  if(Next.SpeedTag == 76)
10041  {
10042  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10043  }
10044  else if(Next.SpeedTag == 77)
10045  {
10046  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10047  }
10048  else if(Next.SpeedTag == 78)
10049  {
10050  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10051  }
10052  else if(Next.SpeedTag == 79)
10053  {
10054  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10055  }
10056  else if(Next.SpeedTag == 96)
10057  {
10058  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10059  }
10060  else if(Next.SpeedTag == 131)
10061  {
10062  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10063  }
10064  }
10065  else
10066  {
10067  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10068  }
10069  }
10070  }
10071 
10072  NextTrackElementPtr = TrackVector.begin();
10073  while(ReturnNextTrackElement(1, Next))
10074  {
10075  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10076  {
10077  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10078  {
10079  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10080  {
10081  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10082  }
10083  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10084  {
10085  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10086  }
10087  }
10088  else
10089  {
10090  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10091  }
10092  }
10093  }
10094  Disp->Update();
10095  Utilities->CallLogPop(640);
10096 }
10097 
10098 // ---------------------------------------------------------------------------
10099 
10100 void TTrack::PlotSmallRedGap(int Caller)
10101 {
10102  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10104  Utilities->CallLogPop(1346);
10105 }
10106 
10107 // ---------------------------------------------------------------------------
10108 
10109 void TTrack::TrackClear(int Caller)
10110 {
10111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10112  TrackVector.clear();
10113  InactiveTrackVector.clear();
10114  TrackMap.clear();
10116  if(TextHandler->TextVector.size() == 0)
10117  {
10118  Display->DisplayOffsetH = 0;
10119  Display->DisplayOffsetV = 0;
10126  HLocMin = 2000000000;
10127  HLocMax = -2000000000;
10128  VLocMin = 2000000000;
10129  VLocMax = -2000000000;
10130  }
10131  else
10132  {
10133  CalcHLocMinEtc(4);
10134  }
10135  Utilities->CallLogPop(1347);
10136 }
10137 
10138 // ---------------------------------------------------------------------------
10139 
10140 void TTrack::CalcHLocMinEtc(int Caller)
10141 {
10142  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10143  HLocMin = 2000000000;
10144  VLocMin = 2000000000;
10145  HLocMax = -2000000000;
10146  VLocMax = -2000000000;
10147  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10148  {
10149  if(TrackVector.at(x).SpeedTag == 0)
10150  {
10151  continue; // skip erase elements or would interfere with Min & Max values
10152  }
10153  if(TrackVector.at(x).HLoc - 1 < HLocMin)
10154  {
10155  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
10156  }
10157  if(TrackVector.at(x).HLoc + 1 > HLocMax)
10158  {
10159  HLocMax = TrackVector.at(x).HLoc + 1;
10160  }
10161  if(TrackVector.at(x).VLoc - 1 < VLocMin)
10162  {
10163  VLocMin = TrackVector.at(x).VLoc - 1;
10164  }
10165  if(TrackVector.at(x).VLoc + 1 > VLocMax)
10166  {
10167  VLocMax = TrackVector.at(x).VLoc + 1;
10168  }
10169  }
10170  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10171  {
10172  if(InactiveTrackVector.at(x).SpeedTag == 0)
10173  {
10174  continue; // shouldn't be any inactive erase elements but include anyway
10175  }
10176  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
10177  {
10178  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
10179  }
10180  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
10181  {
10182  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
10183  }
10184  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
10185  {
10186  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
10187  }
10188  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
10189  {
10190  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
10191  }
10192  }
10193  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10194  {
10195 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10196  will fail as x will exceed the maximum value
10197  if(TextHandler->TextPtrAt(, x)->TextString == "")
10198  {
10199  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10200  }
10201 */
10202  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10203  if((TextH / 16) - 1 < HLocMin)
10204  {
10205  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10206  }
10207  if((TextH / 16) + 1 > HLocMax)
10208  {
10209  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10210  }
10211  if((TextV / 16) - 1 < VLocMin)
10212  {
10213  VLocMin = (TextV / 16) - 1;
10214  }
10215  if((TextV / 16) + 1 > VLocMax)
10216  {
10217  VLocMax = (TextV / 16) + 1;
10218  }
10219  }
10220  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10221  {
10222  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10223  {
10224  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10225  }
10226  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10227  {
10228  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10229  }
10230  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10231  {
10232  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10233  }
10234  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10235  {
10236  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10237  }
10238  }
10239 
10240  Utilities->CallLogPop(641);
10241 }
10242 
10243 // ---------------------------------------------------------------------------
10244 
10245 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10246  bool &UserGraphicFoundFlag)
10247 {
10248  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10249  TUserGraphicVector::iterator UserGraphicPtr;
10250 
10251  UserGraphicFoundFlag = false;
10252  if(!UserGraphicVector.empty())
10253  {
10254  int x = UserGraphicVector.size();
10255  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10256  {
10257  x--;
10258  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10259  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10260  {
10261  UserGraphicItem = x;
10262  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10263  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10264  UserGraphicFoundFlag = true;
10265  Utilities->CallLogPop(2177);
10266  return;
10267  } // if ....
10268 
10269  } // for UserGraphicPtr...
10270  } // if !UserGraphicVector...
10271 
10272  Utilities->CallLogPop(2197);
10273 }
10274 
10275 // ---------------------------------------------------------------------------
10276 
10278 {
10279  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10280  TrackElement.LogTrack(11));
10281  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10282  int SpeedTag = TrackElement.SpeedTag;
10283 
10284  if(SpeedTag < 1)
10285  {
10286  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10287  }
10288  switch(SpeedTag)
10289  {
10290  case 76: // t platform
10291  GraphicOutput = RailGraphics->gl76Striped;
10292  break;
10293 
10294  case 77: // h platform
10295  GraphicOutput = RailGraphics->bm77Striped;
10296  break;
10297 
10298  case 78: // v platform
10299  GraphicOutput = RailGraphics->bm78Striped;
10300  break;
10301 
10302  case 79: // r platform
10303  GraphicOutput = RailGraphics->gl79Striped;
10304  break;
10305 
10306  case 96: // concourse
10307  GraphicOutput = RailGraphics->ConcourseStriped;
10308  break;
10309 
10310  case 129: // v footbridge
10311  GraphicOutput = RailGraphics->gl129Striped;
10312  break;
10313 
10314  case 130: // h footbridge
10315  GraphicOutput = RailGraphics->gl130Striped;
10316  break;
10317 
10318  case 131: // non-station named loc
10319  GraphicOutput = RailGraphics->bmNameStriped;
10320  break;
10321 
10322  case 145: // v u'pass
10323  GraphicOutput = RailGraphics->gl145Striped;
10324  break;
10325 
10326  case 146: // h u'pass
10327  GraphicOutput = RailGraphics->gl146Striped;
10328  break;
10329 
10330  default:
10331  GraphicOutput = TrackElement.GraphicPtr;
10332  break;
10333  }
10334  Utilities->CallLogPop(642);
10335  return(GraphicOutput);
10336 }
10337 
10338 // ---------------------------------------------------------------------------
10339 
10341 {
10342  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10343  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10344  {
10345  Utilities->CallLogPop(2281);
10346  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10347  }
10348  Utilities->CallLogPop(643);
10349  return(TrackVector.at(At));
10350 }
10351 
10352 // ---------------------------------------------------------------------------
10353 
10355 {
10356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10357  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10358  {
10359  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10360  " in InactiveTrackElementAt");
10361  }
10362  Utilities->CallLogPop(644);
10363  return(InactiveTrackVector.at(At));
10364 }
10365 
10366 // ---------------------------------------------------------------------------
10367 
10368 bool TTrack::BlankElementAt(int Caller, int At) const
10369 {
10370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10371  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10372  {
10373  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10374  }
10375  if(TrackVector.at(At).SpeedTag == 0)
10376  {
10377  Utilities->CallLogPop(645);
10378  return(true);
10379  }
10380  else
10381  {
10382  Utilities->CallLogPop(646);
10383  return(false);
10384  }
10385 }
10386 
10387 // ---------------------------------------------------------------------------
10388 
10389 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10390 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10391  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10392  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10393  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10394  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10395 */
10396 {
10397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10398  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10399  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10400  TLocationNameMultiMapIterator SNIterator;
10401  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10402 
10403  if(SNRange.first == SNRange.second)
10404  {
10405  Utilities->CallLogPop(972);
10406  return(false); // should have been caught earlier but include for completeness
10407  }
10408  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10409  {
10410  if(SNIterator->second < 0)
10411  {
10412  continue; // exclude footcrossings
10413  }
10414  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10415  if(InactiveElement.TrackType == Concourse)
10416  {
10417  continue; // only interested in locations where ActiveTrackElementName may be set
10418  }
10419  THVPair HVPair;
10420  HVPair.first = InactiveElement.HLoc;
10421  HVPair.second = InactiveElement.VLoc;
10422  if(TrackMap.find(HVPair) == TrackMap.end())
10423  {
10424  throw Exception
10425  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10426  }
10427  int TVPos = TrackMap.find(HVPair)->second;
10428  FirstNamedElement = TrackElementAt(560, TVPos);
10429  // first check linked on both sides, skip the check if not
10430  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10431  {
10432  continue;
10433  }
10434  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10435  // ActiveTrackElementNames are points and excluding trailing connections for points
10436  FirstNamedExitPos = 0;
10437  {
10438  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10439  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10440  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10441  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10442  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10443  {
10444  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10445  {
10446  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10447  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10448  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10449  // success, now check FirstNamedElement link not trailing points & if so all OK
10450  {
10451  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10452  {
10453  Utilities->CallLogPop(1002);
10454  return(true);
10455  }
10456  }
10457  }
10458  }
10459  }
10460  // failed, try link 1
10461  FirstNamedExitPos = 1;
10462  {
10463  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10464  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10465  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10466  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10467  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10468  {
10469  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10470  {
10471  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10472  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10473  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10474  // success, now check FirstNamedElement link not trailing points & if so all OK
10475  {
10476  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10477  {
10478  Utilities->CallLogPop(1003);
10479  return(true);
10480  }
10481  }
10482  }
10483  }
10484  }
10485  }
10486  Utilities->CallLogPop(1004);
10487  return(false);
10488 }
10489 
10490 // ---------------------------------------------------------------------------
10491 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10492  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10493 // for success need two linked named location elements, so that one element of each train can be at the location
10494 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10495 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10496 // the two trains will occupy these 4 elements
10497 // All are track vector positions, all but the input being references and set within the function.
10498 {
10499 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10500  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10501  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10502  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10503  splitting.
10504 */
10505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10506  AnsiString(FirstNamedElementPos));
10507  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10508  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10509 
10510  SecondNamedElementPos = -1;
10511  FirstNamedLinkedElementPos = -1;
10512  SecondNamedLinkedElementPos = -1;
10513  TLocationNameMultiMapIterator SNIterator;
10514  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10515 
10516  if(SNRange.first == SNRange.second) // i.e. location name not in map
10517  {
10518  Utilities->CallLogPop(1005);
10519  return(false); // should have been caught earlier but include for completeness
10520  }
10521  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10522  {
10523  if(SNIterator->second < 0)
10524  {
10525  continue; // exclude footcrossings
10526  }
10527  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10528  if(InactiveElement.TrackType == Concourse)
10529  {
10530  continue; // only interested in locations where ActiveTrackElementName may be set
10531  }
10532  THVPair HVPair;
10533  HVPair.first = InactiveElement.HLoc;
10534  HVPair.second = InactiveElement.VLoc;
10535  if(TrackMap.find(HVPair) == TrackMap.end())
10536  {
10537  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10538  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10539  // then it won't be found in TrackMap but it's still legitimate.
10540  {
10541  continue;
10542  }
10543  else // for anything else throw the error
10544  {
10545  throw Exception
10546  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10547  );
10548  }
10549  }
10550  int TVPos = TrackMap.find(HVPair)->second;
10551  if(TVPos != FirstNamedElementPos)
10552  {
10553  continue; // looking for an exact match
10554  }
10555  FirstNamedElement = TrackElementAt(567, TVPos);
10556  // first check linked on both sides, skip the check if not
10557  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10558  {
10559  continue;
10560  }
10561  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10562  // ActiveTrackElementNames are points and excluding trailing connections for points
10563  FirstNamedExitPos = 0;
10564  {
10565  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10566  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10567  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10568  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10569  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10570  {
10571  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10572  {
10573  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10574  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10575  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10576  // success, now check FirstNamedElement link not trailing points & if so all OK
10577  {
10578  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10579  {
10580  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10581  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10582  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10583  Utilities->CallLogPop(1006);
10584  return(true);
10585  }
10586  }
10587  }
10588  }
10589  }
10590  // failed, try link 1
10591  FirstNamedExitPos = 1;
10592  {
10593  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10594  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10595  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10596  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10597  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10598  {
10599  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10600  {
10601  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10602  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10603  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10604  // success, now check FirstNamedElement link not trailing points & if so all OK
10605  {
10606  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10607  {
10608  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10609  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10610  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10611  Utilities->CallLogPop(1007);
10612  return(true);
10613  }
10614  }
10615  }
10616  }
10617  }
10618  }
10619  Utilities->CallLogPop(1008);
10620  return(false);
10621 }
10622 
10623 // ---------------------------------------------------------------------------
10624 
10625 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10626 {
10627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10628  TLocationNameMultiMapIterator SNIterator;
10629  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10630 
10631  if(SNRange.first != SNRange.second)
10632  {
10633  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10634  {
10635  if(SNIterator->second < 0)
10636  {
10637  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10638  }
10639  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10640  SNIterator->second).TrackType == NamedNonStationLocation))
10641  {
10642  Utilities->CallLogPop(1121);
10643  return(true);
10644  }
10645  }
10646  }
10647  Utilities->CallLogPop(848);
10648  return(false);
10649 }
10650 
10651 // ---------------------------------------------------------------------------
10652 
10653 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10654 {
10655 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10657  "," + AnsiString(SpeedTag));
10658  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10659  {
10660  Utilities->CallLogPop(949);
10661  return(false);
10662  }
10663  bool FoundFlag;
10664  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10665 
10666  if(!FoundFlag)
10667  {
10668  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10669  }
10670  TTrackElement IAElement;
10671 
10672  if(SpeedTag == 68) // top sig
10673  {
10674  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10675  {
10676  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10677  {
10678  IAElement = InactiveTrackElementAt(50, IMPair.first);
10679  }
10680  else
10681  {
10682  IAElement = InactiveTrackElementAt(51, IMPair.second);
10683  }
10684  if(IAElement.LocationName == "")
10685  {
10686 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10687  SignalPlatformGraphic = RailGraphics->gl76Striped;
10688  }
10689  else
10690  {
10691 // SignalPlatformGraphic = RailGraphics->Plat68;
10692  SignalPlatformGraphic = RailGraphics->gl76;
10693  }
10694  Utilities->CallLogPop(950);
10695  return(true);
10696  }
10697  }
10698  else if(SpeedTag == 69) // bot sig
10699  {
10700  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10701  {
10702  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10703  {
10704  IAElement = InactiveTrackElementAt(77, IMPair.first);
10705  }
10706  else
10707  {
10708  IAElement = InactiveTrackElementAt(78, IMPair.second);
10709  }
10710  if(IAElement.LocationName == "")
10711  {
10712 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10713  SignalPlatformGraphic = RailGraphics->bm77Striped;
10714  }
10715  else
10716  {
10717 // SignalPlatformGraphic = RailGraphics->Plat69;
10718  SignalPlatformGraphic = RailGraphics->bm77;
10719  }
10720  Utilities->CallLogPop(951);
10721  return(true);
10722  }
10723  }
10724  else if(SpeedTag == 70) // left sig
10725  {
10726  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10727  {
10728  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10729  {
10730  IAElement = InactiveTrackElementAt(55, IMPair.first);
10731  }
10732  else
10733  {
10734  IAElement = InactiveTrackElementAt(82, IMPair.second);
10735  }
10736  if(IAElement.LocationName == "")
10737  {
10738 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10739  SignalPlatformGraphic = RailGraphics->bm78Striped;
10740  }
10741  else
10742  {
10743 // SignalPlatformGraphic = RailGraphics->Plat70;
10744  SignalPlatformGraphic = RailGraphics->bm78;
10745  }
10746  Utilities->CallLogPop(952);
10747  return(true);
10748  }
10749  }
10750  else if(SpeedTag == 71) // right sig
10751  {
10752  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10753  {
10754  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10755  {
10756  IAElement = InactiveTrackElementAt(85, IMPair.first);
10757  }
10758  else
10759  {
10760  IAElement = InactiveTrackElementAt(86, IMPair.second);
10761  }
10762  if(IAElement.LocationName == "")
10763  {
10764 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10765  SignalPlatformGraphic = RailGraphics->gl79Striped;
10766  }
10767  else
10768  {
10769 // SignalPlatformGraphic = RailGraphics->Plat71;
10770  SignalPlatformGraphic = RailGraphics->gl79;
10771  }
10772  Utilities->CallLogPop(953);
10773  return(true);
10774  }
10775  }
10776  Utilities->CallLogPop(954);
10777  return(false);
10778 }
10779 
10780 // ---------------------------------------------------------------------------
10781 
10782 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10783 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10784 // false if not, if NextPos == -1, or if only own train on the track
10785 {
10786  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10787  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10788  if(NextEntryPos < 0)
10789  {
10790  Utilities->CallLogPop(1348);
10791  return(false);
10792  }
10793  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10794 
10795  if(TrackElement.TrackType != Bridge)
10796  {
10797  Utilities->CallLogPop(1349);
10798  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10799  }
10800 // bridge if reach here
10801  if(NextEntryPos > 1)
10802  {
10803  Utilities->CallLogPop(1350);
10804  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10805  }
10806  else
10807  {
10808  Utilities->CallLogPop(1351);
10809  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10810  }
10811 }
10812 
10813 // ---------------------------------------------------------------------------
10814 
10816 {
10817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10818  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10819  {
10820  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10821  }
10822  Utilities->CallLogPop(1483);
10823  return(SelectVector.at(At));
10824 }
10825 
10826 // ---------------------------------------------------------------------------
10827 
10828 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
10829 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
10830 {
10831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
10832  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
10833  bool FoundFlag = false;
10834  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
10835  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
10836 
10837  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
10838  Utilities->CallLogPop(1538);
10839  return(FoundFlag);
10840 }
10841 
10842 // ---------------------------------------------------------------------------
10843 
10844 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
10845 {
10846 // return true if find an inactive element called 'Name'
10847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
10848  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
10849  bool FoundFlag = false;
10850 
10851  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10852  {
10853  if(InactiveTrackVector.at(x).LocationName == Name)
10854  {
10855  FoundFlag = true;
10856  int V = InactiveTrackVector.at(x).VLoc;
10857  int H = InactiveTrackVector.at(x).HLoc;
10858  if(V > VLocHi)
10859  {
10860  VLocHi = V;
10861  }
10862  if(V < VLocLo)
10863  {
10864  VLocLo = V;
10865  }
10866  if(H < HLoc)
10867  {
10868  HLoc = H;
10869  }
10870  }
10871  }
10872  if(FoundFlag)
10873  {
10874  VPosHi = 16 * VLocHi;
10875  VPosLo = 16 * VLocLo;
10876  HPos = 16 * HLoc;
10877  Utilities->CallLogPop(1562);
10878  return(true);
10879  }
10880  else
10881  {
10882  Utilities->CallLogPop(1563);
10883  return(false);
10884  }
10885 }
10886 
10887 // ---------------------------------------------------------------------------
10888 
10889 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10890 {
10891 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10892 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10893  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10894  AnsiString(EndTVPosition));
10895  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10896  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10897 
10898 // get H & V values for the element adjacent to Link[0] & Link[1]
10899  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10900  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10901  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10902  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10903 
10904 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10905  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10906  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10907  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10908  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10909 
10910  if(Link0Squares <= Link1Squares)
10911  {
10912  Utilities->CallLogPop(1851);
10913  return(0);
10914  }
10915  else
10916  {
10917  Utilities->CallLogPop(1852);
10918  return(1);
10919  }
10920 }
10921 
10922 // ---------------------------------------------------------------------------
10923 
10924 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
10925 {
10926  // element can be points or any other type
10927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
10928  AnsiString(LinkPos));
10929  Derail = false;
10930  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
10931 
10932  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
10933  {
10934  if(TE.Attribute == 0)
10935  {
10936  Utilities->CallLogPop(663);
10937  return(1); // Att == 0 & ExitPos == 1 represent straight
10938  }
10939  else
10940  {
10941  Utilities->CallLogPop(664);
10942  return(3); // Att == 1 & ExitPos == 3 represent diverging
10943  }
10944  }
10945  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
10946  {
10947  if((LinkPos == 1) && (TE.Attribute == 0))
10948  {
10949  Utilities->CallLogPop(665);
10950  return(0); // Att == 0 represents straight
10951  }
10952  else if(LinkPos == 1)
10953  {
10954  Derail = true;
10955  Utilities->CallLogPop(666);
10956  return(0);
10957  }
10958  else if((LinkPos == 3) && (TE.Attribute == 1))
10959  {
10960  Utilities->CallLogPop(667);
10961  return(0);
10962  }
10963  else if(LinkPos == 3)
10964  {
10965  Derail = true;
10966  Utilities->CallLogPop(668);
10967  return(0);
10968  }
10969  }
10970  else if(LinkPos == 0)
10971  {
10972  Utilities->CallLogPop(669);
10973  return(1);
10974  }
10975  else if(LinkPos == 1)
10976  {
10977  Utilities->CallLogPop(670);
10978  return(0);
10979  }
10980  else if(LinkPos == 2)
10981  {
10982  Utilities->CallLogPop(671);
10983  return(3);
10984  }
10985  else if(LinkPos == 3)
10986  {
10987  Utilities->CallLogPop(672);
10988  return(2);
10989  }
10990  throw Exception("Error, failure in GetExitPos"); // should never reach here
10991 }
10992 
10993 // ----------------------------------------------------------------------------
10994 
10996 {
10997  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
10998  LCVector.clear();
10999  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11000  {
11001  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
11002  {
11003  LCVector.push_back(x);
11004  }
11005  }
11006  Utilities->CallLogPop(1931);
11007  return;
11008 }
11009 
11010 // ---------------------------------------------------------------------------
11011 
11012 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11013 /*
11014  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11015  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11016  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11017  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11018 */
11019 {
11020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11021  AnsiString(Link));
11022  bool FoundFlag;
11023 
11024  TrainID = -1;
11025  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11026 
11027  if(!FoundFlag)
11028  {
11029  Utilities->CallLogPop(2001);
11030  return(false);
11031  }
11032  TTrackElement TE = TrackElementAt(882, VecPos);
11033 
11034  TrainID = TE.TrainIDOnElement;
11035  if(TE.TrackType == Bridge)
11036  {
11037  if(TE.TrainIDOnElement > -1)
11038  {
11039  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11040  {
11041  TrainID = TE.TrainIDOnBridgeTrackPos01;
11042  }
11043  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11044  {
11045  TrainID = TE.TrainIDOnBridgeTrackPos23;
11046  }
11047  else
11048  {
11049  TrainID = -1; // shouldn't ever reach here but be safe
11050  }
11051  }
11052  }
11053  if(TrainID == -1)
11054  {
11055  Utilities->CallLogPop(2002);
11056  return(false);
11057  }
11058 // now get the train
11059  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11060 
11061  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11062  {
11063  Utilities->CallLogPop(2003);
11064  return(true);
11065  }
11066  TrainID = -1;
11067  Utilities->CallLogPop(2004);
11068  return(false);
11069 }
11070 
11071 // ---------------------------------------------------------------------------
11072 
11073 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11074 /* New at v1.2.0
11075  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11076  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11077  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11078  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11079  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11080  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11081  Each of these is examined in turn for each route element in the relevant position.
11082 */
11083 {
11084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11085  "," + AnsiString(DiagonalLinkNumber));
11086  TrainID = -1;
11087  TPrefDirElement TempPrefDirElement;
11088  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11089 
11090  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11091  {
11092  Utilities->CallLogPop(2027);
11093  return(true);
11094  }
11095  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11096  {
11097  Utilities->CallLogPop(2028);
11098  return(true);
11099  }
11100  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11101  {
11102  Utilities->CallLogPop(2029);
11103  return(true);
11104  }
11105  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11106  {
11107  Utilities->CallLogPop(2030);
11108  return(true);
11109  }
11110  Utilities->CallLogPop(2031);
11111  return(false);
11112 }
11113 
11114 // ---------------------------------------------------------------------------
11115 
11116 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11117 {
11118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11119  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11120  TUserGraphicItem UGI;
11121  AnsiString JustFileName = "";
11122 
11123  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11124  {
11125  UGI = UserGraphicVectorAt(17, x);
11126  int LastDelim = UGI.FileName.LastDelimiter('\\');
11127  if(LastDelim == 0) // can't find it so skip this item
11128  {
11129  continue;
11130  }
11131  else
11132  {
11133  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11134  }
11135  Utilities->SaveFileString(VecFile, JustFileName);
11136  Utilities->SaveFileInt(VecFile, UGI.HPos);
11137  Utilities->SaveFileInt(VecFile, UGI.VPos);
11138  }
11139  Utilities->CallLogPop(2178);
11140 }
11141 
11142 // ---------------------------------------------------------------------------
11143 
11144 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11145 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11146 {
11147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11148  int NumPlats = 0;
11149  TTrackElement TempElement;
11150  int TempInt;
11151 
11152  typedef std::list<int> TNamePosList;
11153  TNamePosList NamePosList;
11154  typedef TNamePosList::iterator TNPLIt;
11155  TNPLIt NPLIt;
11156  typedef std::list<int> TOnePlatList;
11157  TOnePlatList OnePlatList;
11158  typedef TOnePlatList::iterator TOPLIt;
11159  TOPLIt OPLIt;
11160 
11161  NamePosList.clear();
11162  OnePlatList.clear();
11163  for(unsigned int x = 0; x < TrackVector.size(); x++)
11164  {
11165  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11166  {
11167  NamePosList.push_back(x);
11168  }
11169  }
11170  //NamePosList complete
11171 
11172  if(!NamePosList.empty()) //first value for the loop examination
11173  {
11174  OnePlatList.push_back(NamePosList.back());
11175  NamePosList.pop_back(); //erase from NPV as done with it here
11176  }
11177  while(!OnePlatList.empty()) //loop to examine all linked elements
11178  {
11179  TempInt = OnePlatList.front();
11180  TempElement = TrackElementAt(989, TempInt);
11181 
11182  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11183  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11184  {
11185  OnePlatList.push_back(TempElement.Conn[0]);
11186  NamePosList.erase(NPLIt);
11187  }
11188  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11189  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11190  {
11191  OnePlatList.push_back(TempElement.Conn[1]);
11192  NamePosList.erase(NPLIt);
11193  }
11194  //here when loaded any connecting links into OnePlatList, so can erase the front element
11195  OnePlatList.erase(OnePlatList.begin());
11196  if(OnePlatList.empty())
11197  {
11198  NumPlats++; //finished with current linked elements so can increment NumPlats
11199  if(!NamePosList.empty())
11200  {
11201  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11202  NamePosList.pop_back(); //erase from NPV as done with it there
11203  }
11204  }
11205  }
11206  Utilities->CallLogPop(2218);
11207  return(NumPlats);
11208 }
11209 
11210 // ---------------------------------------------------------------------------
11211 // UserGraphic, PrefDir & Route functions
11212 // ---------------------------------------------------------------------------
11213 
11215 {
11216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11217  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11218  {
11219  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11220  }
11221  Utilities->CallLogPop(2194);
11222  return(UserGraphicVector.at(At));
11223 }
11224 
11225 // ---------------------------------------------------------------------------
11226 
11227 int TOnePrefDir::LastElementNumber(int Caller) const
11228 {
11229  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11230  int RetVal = PrefDirVector.size() - 1;
11231 
11232  if(RetVal < 0)
11233  {
11234  throw Exception("Return value negative in call to LastElementNumber");
11235  }
11236  Utilities->CallLogPop(114);
11237  return(RetVal);
11238 }
11239 
11240 // ---------------------------------------------------------------------------
11242 {
11243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11244  if(PrefDirVector.empty())
11245  {
11246  throw Exception("PrefDirVector empty in call to LastElementPtr");
11247  }
11248  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11249 
11250  Utilities->CallLogPop(115);
11251  return(RetIT);
11252 }
11253 
11254 // ---------------------------------------------------------------------------
11256 {
11257  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11258  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11259  {
11260  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11261  }
11262  Utilities->CallLogPop(116);
11263  return(PrefDirVector.at(At));
11264 }
11265 
11266 // ---------------------------------------------------------------------------
11268 {
11269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11270  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11271  {
11272  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11273  " in GetModifiablePrefDirElementAt");
11274  }
11275  Utilities->CallLogPop(117);
11276  return(PrefDirVector.at(At));
11277 }
11278 
11279 // ---------------------------------------------------------------------------
11281 {
11282  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11283  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11284  {
11285  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11286  }
11287  Utilities->CallLogPop(118);
11288  return(SearchVector.at(At));
11289 }
11290 
11291 // ---------------------------------------------------------------------------
11293 {
11294  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11295  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11296  {
11297  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11298  }
11299  Utilities->CallLogPop(119);
11300  return(SearchVector.at(At));
11301 }
11302 
11303 // ---------------------------------------------------------------------------
11304 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11305 /*
11306  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11307  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11308  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11309  set in later functions.
11310 */
11311 {
11312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11313  ClearPrefDir();
11314  int TrackVectorPosition;
11315  TTrackElement TrackElement;
11316 
11317  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11318  {
11319  Utilities->CallLogPop(126);
11320  return(false);
11321  }
11322 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11323  if(TrackElement.TrackType == Points)
11324  {
11325  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11326  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11327  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11328  //best to prevent it to avoid problems
11329  Utilities->CallLogPop(127);
11330  return false;
11331  }
11332 */
11333  TPrefDirElement PrefDirElement(TrackElement);
11334 
11335  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11336  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11337  StorePrefDirElement(1, PrefDirElement); // enter first element
11338 // Note that ELink not set even if a buffer or continuation - these set in
11339 // ConvertPrefDirSearchVector after 2nd element added
11340 
11341  Utilities->CallLogPop(128);
11342  return(true);
11343 }
11344 
11345 // ---------------------------------------------------------------------------
11346 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11347 
11348 /*
11349  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11350  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11351  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11352  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11353  so that the calling function knows that the PrefDir is complete.
11354  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11355  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11356  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11357  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11358  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11359  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11360  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11361  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11362 */
11363 
11364 {
11365  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11366  FinishElement = false;
11367  int TrackVectorPosition;
11368 
11369  TotalSearchCount = 0;
11370  TTrackElement TrackElement, TempTrackElement;
11371 
11372  if(PrefDirVector.size() == 0)
11373  {
11374  Utilities->CallLogPop(129);
11375  return(false);
11376  }
11377  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11378  {
11379  Utilities->CallLogPop(130);
11380  return(false);
11381  }
11382 // set the search limits using the last stored element in PrefDirVector as the start point
11383 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11384 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11385 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11386 
11387  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11388 
11389  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11390  {
11391  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11392  SearchLimitHighH = TrackElement.HLoc + 15;
11393  }
11394  else
11395  {
11396  SearchLimitLowH = TrackElement.HLoc - 15;
11397  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11398  }
11399  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11400  {
11401  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11402  SearchLimitHighV = TrackElement.VLoc + 15;
11403  }
11404  else
11405  {
11406  SearchLimitLowV = TrackElement.VLoc - 15;
11407  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11408  }
11409 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11410  check & TotalSearchCounts check
11411  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11412  {
11413  ShowMessage("Unable to reach the selected element - too far ahead");
11414  Utilities->CallLogPop(1692);
11415  return false;
11416  }
11417 */
11418 // get last PrefDir element
11419  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11420  {
11421  // check if TrackElement adjacent to any of the 4 XLinkPos'
11422  for(int x = 0; x < 4; x++)
11423  {
11424  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11425  {
11426  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11427  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11428  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11429  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11430  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11431  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11432  // shouldn't ever get it in a serious railway though.
11433 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11434  }
11435  }
11436  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11437  {
11438  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11439  SearchVector.clear(); // use this & convert to set all PrefDir element values
11440  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11441  {
11443  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11444  {
11445  FinishElement = true;
11446  }
11447  Utilities->CallLogPop(131);
11448  return(true);
11449  }
11450  } // not an adjacent element
11451 
11452  // now check each of the 4 possible XLinkPos values
11453  for(int x = 0; x < 4; x++)
11454  {
11455  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11456  {
11457  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11458  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11459  SearchVector.clear();
11460  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11461  {
11463  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11464  {
11465  FinishElement = true;
11466  }
11467  Utilities->CallLogPop(132);
11468  return(true);
11469  }
11470  }
11471  } // here if checked all possible exits without success
11472  ShowMessage(
11473  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11474  Utilities->CallLogPop(133);
11475  return(false);
11476  }
11477 // dealt above with LastPrefDirElement being the start element (which can be points)
11478 
11479  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11480  .ELinkPos] == Lead)) // leading point
11481  {
11482  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11483  {
11484  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11485  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11486  // can't be buffers or gap if points
11487  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11488  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11489  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11490  SearchVector.clear();
11491  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11492  {
11494  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11495  {
11496  FinishElement = true;
11497  }
11498  Utilities->CallLogPop(134);
11499  return(true);
11500  }
11501  }
11502  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11503  {
11504  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11505  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11506  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11507  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11508  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11509  SearchVector.clear();
11510  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11511  {
11513  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11514  {
11515  FinishElement = true;
11516  }
11517  Utilities->CallLogPop(135);
11518  return(true);
11519  }
11520  }
11521 // above dealt with immediate finds for leading point,
11522 // now deal with ordinary searches for leading point
11523  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11524  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11525  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11526  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11527  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11528  SearchVector.clear();
11529  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11530  {
11532  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11533  {
11534  FinishElement = true;
11535  }
11536  Utilities->CallLogPop(136);
11537  return(true);
11538  }
11539  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11540  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11541  // note that CheckCount already increased to allow for XLinkPos & XLink
11542  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11543  SearchVector.clear();
11544  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11545  {
11547  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11548  {
11549  FinishElement = true;
11550  }
11551  Utilities->CallLogPop(137);
11552  return(true);
11553  }
11554 // here if failed to find match for leading point
11555  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11556  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11557  ShowMessage(
11558  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11559  Utilities->CallLogPop(138);
11560  return(false);
11561  }
11562 // leading point fully dealt with above
11563 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11564 // separately as covered in ordinary search.
11565 
11566  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11567  SearchVector.clear();
11568 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11569  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11570  {
11572  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11573  {
11574  FinishElement = true;
11575  }
11576  Utilities->CallLogPop(139);
11577  return(true);
11578  }
11579  ShowMessage(
11580  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11581  Utilities->CallLogPop(140);
11582  return(false); // failed to find required element
11583 }
11584 
11585 // ---------------------------------------------------------------------------
11586 
11587 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11588 /*
11589  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11590  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11591  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11592  Keep a count of entries in SearchVector during the current function call, so that this number can be
11593  erased for an unproductive branch search.
11594  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11595  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11596  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11597  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11598  If not any of above, store element in searchvector, set the new current element values from the
11599  SearchElement, then go back to the while loop for the next step in the search.
11600 */
11601 {
11602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11603  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11604  int VectorCount = 0;
11605 
11606  while(true)
11607  {
11608  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11609  {
11610  for(int x = 0; x < VectorCount; x++)
11611  {
11612  SearchVector.erase(SearchVector.end() - 1);
11613  }
11614  Utilities->CallLogPop(141);
11615  return(false);
11616  }
11617  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11618  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11619  TPrefDirElement SearchElement(NextTrackElement);
11620  SearchElement.TrackVectorPosition = NextPosition;
11621  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11622  SearchElement.ELinkPos = NextELinkPos;
11623  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11624  int NextXLinkPos;
11625  if(SearchElement.ELinkPos == 0)
11626  {
11627  NextXLinkPos = 1;
11628  }
11629  if(SearchElement.ELinkPos == 1)
11630  {
11631  NextXLinkPos = 0;
11632  }
11633  if(SearchElement.ELinkPos == 2)
11634  {
11635  NextXLinkPos = 3;
11636  }
11637  if(SearchElement.ELinkPos == 3)
11638  {
11639  NextXLinkPos = 2;
11640  }
11641  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11642  {
11643  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11644  // but may be buffers, continuation or gap
11645  SearchElement.XLinkPos = NextXLinkPos;
11646  }
11647 // can't set XLink or XLinkPos yet if the element is a leading point.
11648 // check if found it
11649  if(SearchElement.TrackVectorPosition == RequiredPosition)
11650  {
11651  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11652  VectorCount++; // not really needed but include for tidyness
11653  TotalSearchCount++;
11654  Utilities->CallLogPop(142);
11655  return(true);
11656  }
11657 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11658 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11659 // at a time - drop this
11660 /*
11661  if(PrefDirVector.size() > 200)
11662  {
11663  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11664  Utilities->CallLogPop(1419);
11665  return false;
11666  }
11667 */
11668 // check if a buffer or continuation
11669  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11670  {
11671  for(int x = 0; x < VectorCount; x++)
11672  {
11673  SearchVector.erase(SearchVector.end() - 1);
11674  }
11675  Utilities->CallLogPop(143);
11676  return(false);
11677  }
11678 // check if reached an earlier position on search PrefDir with same entry value
11679  for(unsigned int x = 0; x < SearchVector.size(); x++)
11680  {
11681  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11682  {
11683  for(int x = 0; x < VectorCount; x++)
11684  {
11685  SearchVector.erase(SearchVector.end() - 1);
11686  }
11687  Utilities->CallLogPop(144);
11688  return(false);
11689  }
11690  }
11691 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11692 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11693  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11694  {
11695  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11696  {
11697  for(int x = 0; x < VectorCount; x++)
11698  {
11699  SearchVector.erase(SearchVector.end() - 1);
11700  }
11701  Utilities->CallLogPop(1417);
11702  return(false);
11703  }
11704  }
11705 
11706 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11707 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11708 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11710  {
11711  for(int x = 0; x < VectorCount; x++)
11712  {
11713  SearchVector.erase(SearchVector.end() - 1);
11714  }
11715  Utilities->CallLogPop(1691);
11716  return(false);
11717  }
11718 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11719  if(SearchVector.size() > 150)
11720  {
11721  for(int x = 0; x < VectorCount; x++)
11722  {
11723  SearchVector.erase(SearchVector.end() - 1);
11724  }
11725  Utilities->CallLogPop(1418);
11726  return(false);
11727  }
11728 // check if reached a leading point
11729  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11730  {
11731 // push element with XLink set to position [1]
11732  SearchElement.XLink = SearchElement.Link[1];
11733  SearchElement.XLinkPos = 1;
11734  SearchVector.push_back(SearchElement);
11735  VectorCount++;
11736  TotalSearchCount++;
11737  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11738  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11739  // can't be used. NextTrackElement is the corresponding TTrackElement.
11740  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11741  {
11742  Utilities->CallLogPop(145);
11743  return(true);
11744  }
11745  else
11746  {
11747 // remove leading point with XLinkPos [1]
11748  SearchVector.erase(SearchVector.end() - 1);
11749  VectorCount--;
11750 // push element with XLink set to position [3]
11751  SearchElement.XLink = SearchElement.Link[3];
11752  SearchElement.XLinkPos = 3;
11753  SearchVector.push_back(SearchElement);
11754  VectorCount++;
11755  TotalSearchCount++;
11756 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11757  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11758  {
11759  Utilities->CallLogPop(146);
11760  return(true);
11761  }
11762  else
11763  {
11764  for(int x = 0; x < VectorCount; x++)
11765  {
11766  SearchVector.erase(SearchVector.end() - 1);
11767  }
11768  Utilities->CallLogPop(147);
11769  return(false);
11770  }
11771  }
11772  } // if leading point
11773 
11774 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11775 // ready for next element on PrefDir
11776  SearchVector.push_back(SearchElement);
11777  VectorCount++;
11778  TotalSearchCount++;
11779  XLinkPos = NextXLinkPos;
11780  CurrentTrackElement = SearchElement;
11781  } // while(true)
11782 }
11783 
11784 // ---------------------------------------------------------------------------
11785 
11787 /*
11788  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11789  for each element on the search PrefDir, though if the last element is a leading point
11790  then the final XLink won't be set.
11791  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11792  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11793  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11794 */
11795 {
11796  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11797  if(SearchVector.size() == 0)
11798  {
11799  throw Exception("Error, SearchVector empty");
11800  }
11801 // get first SearchElement in order to set last PrefDirelement
11802  TPrefDirElement SearchElement = SearchVector.at(0);
11803 
11804 // set last PrefDir element XLink & ELink values if not already set
11805 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11806  for(int x = 0; x < 4; x++)
11807  {
11808  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11809  {
11810  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11811  {
11812  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11813  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11814  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11815  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11816  }
11817  int ELinkPos;
11818  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11819  {
11820  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11821  }
11822  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
11823  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
11824  {
11825  ELinkPos = 0;
11826  }
11827  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
11828  {
11829  ELinkPos = 3;
11830  }
11831  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
11832  {
11833  ELinkPos = 2;
11834  }
11835  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
11836  {
11837  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
11838  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
11839  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
11840  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
11841  }
11842  break; // no point going any further
11843  }
11844  }
11845 // set EXNumber for last PrefDir element, unless already set
11846 // won't be set if was first element or a leading point
11847  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
11848  {
11849 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
11850  int EXArray[32][2] = {
11851  {4,6},{2,8}, //horizontal & vertical
11852  {2,4},{6,2},{8,6},{4,8}, //sharp curves
11853  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
11854  {1,9},{3,7} //forward & reverse diagonals
11855 */
11856 
11857  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
11858  {
11859  throw Exception("Error in EntryExitNumber 1");
11860  }
11861  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
11862  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
11863  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
11864  }
11865 // Last PrefDir element now complete
11866 
11867 // construct remaining PrefDir elements from searchvector
11868  for(unsigned int x = 0; x < SearchVector.size(); x++)
11869  {
11870  SearchElement = SearchVector.at(x);
11871  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
11872  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
11873  PrefDirElement.ELink = SearchElement.ELink;
11874  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
11875  PrefDirElement.XLink = SearchElement.XLink;
11876  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
11877 // if XLink & XLinkPos not set don't account for them in CheckCount
11878  if(PrefDirElement.XLink == -1)
11879  {
11880  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11881  }
11882  // & TrackVectorPosition
11883  else
11884  {
11885  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11886  }
11887  // XLink, XLinkPos, TrackVectorPosition
11888 
11889 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
11890  if(PrefDirElement.XLink != -1)
11891  {
11892  if(!(PrefDirElement.EntryExitNumber()))
11893  {
11894  throw Exception("Error in EntryExitNumber 2");
11895  }
11896  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11897  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11898  PrefDirElement.CheckCount++;
11899  // all values now incorporated if not a leading point
11900  }
11901 // store PrefDir element
11902  StorePrefDirElement(2, PrefDirElement);
11903  }
11904 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11905  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11906  {
11907  if(ValidatePrefDir(2))
11908  {
11909  ;
11910  } // error messages given within function
11911 
11912  }
11914 /* drop this, check dropped from search
11915  if(PrefDirVector.size() > 200)
11916  {
11917  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11918  }
11919 */
11920  Utilities->CallLogPop(148);
11921 }
11922 
11923 // ---------------------------------------------------------------------------
11924 
11925 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
11926 /*
11927  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
11928  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
11929 */
11930 {
11931  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
11932  LeadingPoints = false;
11933  if(PrefDirVector.empty())
11934  {
11935  Utilities->CallLogPop(1786);
11936  return(false); // should never be empty but allow for it for safety
11937  }
11938  if(PrefDirVector.size() == 1)
11939  {
11940  Utilities->CallLogPop(149);
11941  return(false); // can't end if only one element
11942  }
11943 /*
11944  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
11945  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
11946  {
11947  Utilities->CallLogPop(150);
11948  return true;
11949  }
11950 */
11951 // allow for anything but leading points
11952  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
11953  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
11954  {
11955  Utilities->CallLogPop(1776);
11956  return(true);
11957  }
11958  else
11959  {
11960  LeadingPoints = true;
11961  Utilities->CallLogPop(151);
11962  return(false);
11963  }
11964 }
11965 
11966 // ---------------------------------------------------------------------------
11967 
11969 /*
11970  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
11971  and that every element is connected to the next element
11972 */
11973 {
11974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
11975  int Position;
11976  AnsiString ErrorString;
11977  bool Error = false;
11978 
11979  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11980  {
11981  if(PrefDirVector.at(x).HLoc == -2000000000)
11982  {
11983  Error = true;
11984  ErrorString = "HLoc";
11985  Position = x;
11986  }
11987  if(PrefDirVector.at(x).VLoc == -2000000000)
11988  {
11989  Error = true;
11990  ErrorString = "VLoc";
11991  Position = x;
11992  }
11993  if(PrefDirVector.at(x).ELink == -1)
11994  {
11995  Error = true;
11996  ErrorString = "ELink";
11997  Position = x;
11998  }
11999  if(PrefDirVector.at(x).ELinkPos == -1)
12000  {
12001  Error = true;
12002  ErrorString = "ELinkPos";
12003  Position = x;
12004  }
12005  if(PrefDirVector.at(x).XLink == -1)
12006  {
12007  Error = true;
12008  ErrorString = "XLink";
12009  Position = x;
12010  }
12011  if(PrefDirVector.at(x).XLinkPos == -1)
12012  {
12013  Error = true;
12014  ErrorString = "XLinkPos";
12015  Position = x;
12016  }
12017  if(PrefDirVector.at(x).SpeedTag == 0)
12018  {
12019  Error = true;
12020  ErrorString = "Tag";
12021  Position = x;
12022  }
12023  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12024  {
12025  Error = true;
12026  ErrorString = "TrackVectorPosition";
12027  Position = x;
12028  }
12029  if(PrefDirVector.at(x).EXNumber == -1)
12030  {
12031  Error = true;
12032  ErrorString = "EXNumber";
12033  Position = x;
12034  }
12035  if(PrefDirVector.at(x).CheckCount != 9)
12036  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12037  {
12038  Error = true;
12039  ErrorString = "CheckCount";
12040  Position = x;
12041  }
12042 // extra checks
12043  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12044  {
12045  Error = true;
12046  ErrorString = "EntryGraphicPtr";
12047  Position = x;
12048  }
12049  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12050  {
12051  Error = true;
12052  ErrorString = "EntryDirectionGraphicPtr";
12053  Position = x;
12054  }
12055 // end of extra checks
12056  if(x > 0)
12057  {
12058  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12059  {
12060  Error = true;
12061  ErrorString = "Last XLink not connected to this element";
12062  Position = x;
12063  }
12064  }
12065  }
12066  if(Error)
12067  {
12068  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12069  }
12070  else
12071  {
12072  Utilities->CallLogPop(153);
12073  return(true);
12074  }
12075 }
12076 
12077 // ---------------------------------------------------------------------------
12078 
12079 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12080 /*
12081  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12082  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12083  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12084  or a leading point.
12085 */
12086 {
12087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12088  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12089  {
12090  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12091  {
12092  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12093  {
12094  ErasePrefDirElementAt(1, PrefDirVecPos);
12095  }
12096  if(PrefDirVector.size() == 0)
12097  {
12098  Utilities->CallLogPop(154);
12099  return(true);
12100  }
12101  if(PrefDirVector.size() == 1)
12102  {
12103  PrefDirVector.at(x - 1).ELinkPos = -1;
12104  PrefDirVector.at(x - 1).ELink = -1;
12105  PrefDirVector.at(x - 1).XLinkPos = -1;
12106  PrefDirVector.at(x - 1).XLink = -1;
12107  PrefDirVector.at(x - 1).EXNumber = -1;
12108  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12109  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12110  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12111  Utilities->CallLogPop(155);
12112  return(true);
12113  }
12114  // here with truncate element not first element, so ELink & ELinkPos set
12115  // unset XLink & Pos if a leading point
12116  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12117  {
12118  PrefDirVector.at(x - 1).XLinkPos = -1;
12119  PrefDirVector.at(x - 1).XLink = -1;
12120  PrefDirVector.at(x - 1).EXNumber = -1;
12121  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12122  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12123  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12124  Utilities->CallLogPop(156);
12125  return(true);
12126  }
12127  Utilities->CallLogPop(157);
12128  return(true);
12129  }
12130  }
12131  Utilities->CallLogPop(158);
12132  return(false);
12133 }
12134 
12135 // ---------------------------------------------------------------------------
12136 
12137 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12138 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12139 /*
12140  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12141  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12142  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12143  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12144  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12145  displayed.
12146 */
12147 {
12148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12149  AnsiString((short)BuildingPrefDir));
12150  int HPos, VPos;
12151 
12152  if(PrefDirSize() == 0)
12153  {
12154  Utilities->CallLogPop(159);
12155  return;
12156  }
12157  for(unsigned int x = 0; x < PrefDirSize(); x++)
12158  {
12159  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12160 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12161 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12162 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12163  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12164  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12165  // only the front half of which will be overplotted by the back of the train, then when the train is
12166  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12167  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12168  {
12169  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12170  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12171  {
12172  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12173  }
12174  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12175  // Route, no direction if a single element
12176  {
12177  if(x == 0)
12178  {
12179  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12180  }
12181  if(x == (PrefDirSize() - 1))
12182  {
12183  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12184  }
12185  }
12186  }
12187  }
12188 
12189 // set start & end element colours if building a PrefDir
12190  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12191  {
12192  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12193  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12194  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12195  // set last element colour
12196  if(PrefDirSize() > 1)
12197  {
12198  unsigned int LatestPos = PrefDirSize() - 1;
12199  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12200  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12201  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12202  }
12203  }
12204  Disp->Update();
12205  Utilities->CallLogPop(160);
12206 }
12207 
12208 // ---------------------------------------------------------------------------
12209 
12211 /*
12212  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12213  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12214 */
12215 {
12216  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12217  if(PrefDirSize() == 0)
12218  {
12219  Utilities->CallLogPop(1547);
12220  return;
12221  }
12222  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12223  bool FoundFlag;
12225  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12226 
12227  while(MMIT != PrefDir4MultiMap.end())
12228  {
12229  H = MMIT->first.first;
12230  V = MMIT->first.second;
12231  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12232  // always found in order, any missing have PrefDirPosx == -1
12233  if(PrefDirPos0 > -1)
12234  {
12235  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12236  }
12237  if(PrefDirPos1 > -1)
12238  {
12239  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12240  }
12241  if(PrefDirPos2 > -1)
12242  {
12243  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12244  }
12245  if(PrefDirPos3 > -1)
12246  {
12247  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12248  }
12249  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12250  {
12251  // need to plot all 4 in order to obtain all the direction graphics
12252  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12253  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12254  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12255  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12256  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12257  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12258  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12259  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12260  MMIT++;
12261  MMIT++;
12262  MMIT++;
12263  MMIT++;
12264  }
12265  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12266  {
12267  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12268  {
12269  // 0 & 1 constitute the bidirectional PrefDir
12270  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12271  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12272  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12273  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12274  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12275  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12276  MMIT++;
12277  MMIT++;
12278  MMIT++;
12279  }
12280  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12281  {
12282  // 0 & 2 constitute the bidirectional PrefDir
12283  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12284  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12285  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12286  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12287  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12288  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12289  MMIT++;
12290  MMIT++;
12291  MMIT++;
12292  }
12293  else
12294  {
12295  // 1 & 2 constitute the bidirectional PrefDir
12296  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12297  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12298  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12299  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12300  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12301  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12302  MMIT++;
12303  MMIT++;
12304  MMIT++;
12305  }
12306  }
12307  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12308  {
12309  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12310  {
12311  // 0 & 1 constitute the bidirectional PrefDir
12312  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12313  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12314  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12315  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12316  MMIT++;
12317  MMIT++;
12318  }
12319  else
12320  {
12321  // 2 unidirectional PrefDirs
12322  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12323  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12324  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12325  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12326  MMIT++;
12327  MMIT++;
12328  }
12329  }
12330  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12331  {
12332  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12333  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12334  MMIT++;
12335  }
12336  }
12337  Disp->Update();
12338  Utilities->CallLogPop(1548);
12339 }
12340 
12341 // ---------------------------------------------------------------------------
12342 
12343 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12344 {
12345  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12346  int TempInt;
12347 
12348  ClearPrefDir();
12349  int NumberOfPrefDirElements = 0;
12350 
12351  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12352  for(int x = 0; x < NumberOfPrefDirElements; x++)
12353  {
12354  VecFile >> TempInt; // TrackVectorPosition
12355  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12356  LoadPrefDirElement.TrackVectorPosition = TempInt;
12357  VecFile >> TempInt;
12358  LoadPrefDirElement.ELink = TempInt;
12359  VecFile >> TempInt;
12360  LoadPrefDirElement.ELinkPos = TempInt;
12361  VecFile >> TempInt;
12362  LoadPrefDirElement.XLink = TempInt;
12363  VecFile >> TempInt;
12364  LoadPrefDirElement.XLinkPos = TempInt;
12365  VecFile >> TempInt;
12366  LoadPrefDirElement.EXNumber = TempInt;
12367  VecFile >> TempInt;
12368  LoadPrefDirElement.CheckCount = TempInt;
12369  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12370  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12371  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12372  if(!(LoadPrefDirElement.IsARoute))
12373  {
12374  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12375  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12376  }
12377  else
12378  {
12379  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12380  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12381  LoadPrefDirElement.PrefDirRoute);
12382  }
12383  StorePrefDirElement(5, LoadPrefDirElement);
12384  Utilities->LoadFileString(VecFile); // marker
12385  }
12387  Utilities->CallLogPop(161);
12388 }
12389 
12390 // ---------------------------------------------------------------------------
12391 
12392 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12393 {
12394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12395  int TempInt;
12396 
12397  ClearPrefDir();
12398  int NumberOfPrefDirElements = 0;
12399 
12400  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12401  for(int x = 0; x < NumberOfPrefDirElements; x++)
12402  {
12403  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12404  VecFile >> TempInt; // TrackVectorPosition
12405  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
12406  LoadPrefDirElement.TrackVectorPosition = TempInt;
12407  VecFile >> TempInt;
12408  LoadPrefDirElement.ELink = TempInt;
12409  VecFile >> TempInt;
12410  LoadPrefDirElement.ELinkPos = TempInt;
12411  VecFile >> TempInt;
12412  LoadPrefDirElement.XLink = TempInt;
12413  VecFile >> TempInt;
12414  LoadPrefDirElement.XLinkPos = TempInt;
12415  VecFile >> TempInt;
12416  LoadPrefDirElement.EXNumber = TempInt;
12417  VecFile >> TempInt;
12418  LoadPrefDirElement.CheckCount = TempInt;
12419  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12420  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12421  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12422  if(!(LoadPrefDirElement.IsARoute))
12423  {
12424  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12425  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12426  }
12427  else
12428  {
12429  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12430  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12431  LoadPrefDirElement.PrefDirRoute);
12432  }
12433  StorePrefDirElement(0, LoadPrefDirElement);
12434  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12435  }
12437  Utilities->CallLogPop(1509);
12438 }
12439 
12440 // ---------------------------------------------------------------------------
12441 
12442 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12443 /*
12444  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12445  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12446 */
12447 {
12448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12449  int TempInt;
12450  int NumberOfPrefDirElements = 0;
12451 
12452  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12453  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12454  {
12455  Utilities->CallLogPop(1152);
12456  return(false);
12457  }
12458  for(int x = 0; x < NumberOfPrefDirElements; x++)
12459  {
12460  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12461  {
12462  Utilities->CallLogPop(1766);
12463  return(false);
12464  }
12465  VecFile >> TempInt;
12466  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12467  {
12468  Utilities->CallLogPop(163);
12469  return(false);
12470  }
12471  VecFile >> TempInt;
12472  if((TempInt < -1) || (TempInt > 9)) // ELink
12473  {
12474  Utilities->CallLogPop(162);
12475  return(false);
12476  }
12477  VecFile >> TempInt;
12478  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12479  {
12480  Utilities->CallLogPop(164);
12481  return(false);
12482  }
12483  VecFile >> TempInt;
12484  if((TempInt < -1) || (TempInt > 9)) // XLink
12485  {
12486  Utilities->CallLogPop(165);
12487  return(false);
12488  }
12489  VecFile >> TempInt;
12490  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12491  {
12492  Utilities->CallLogPop(166);
12493  return(false);
12494  }
12495  VecFile >> TempInt;
12496  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12497  {
12498  Utilities->CallLogPop(167);
12499  return(false);
12500  }
12501  VecFile >> TempInt;
12502  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12503  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12504  // ELinkPos, XLink, XLinkPos & EXNumber
12505  {
12506  Utilities->CallLogPop(168);
12507  return(false);
12508  }
12509  VecFile >> TempInt;
12510  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12511  {
12512  Utilities->CallLogPop(1147);
12513  return(false);
12514  }
12515  VecFile >> TempInt;
12516  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12517  {
12518  Utilities->CallLogPop(1510);
12519  return(false);
12520  }
12521  VecFile >> TempInt;
12522  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12523  {
12524  Utilities->CallLogPop(1148);
12525  return(false);
12526  }
12527  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12528  {
12529  Utilities->CallLogPop(1700);
12530  return(false);
12531  }
12532  }
12533  Utilities->CallLogPop(169);
12534  return(true);
12535 }
12536 
12537 // ---------------------------------------------------------------------------
12538 
12539 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12540 {
12541  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12542  int NumberOfPrefDirElements = PrefDirVector.size();
12543 
12544  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12545  for(int y = 0; y < NumberOfPrefDirElements; y++)
12546  {
12547  VecFile << y << '\n'; // extra
12548  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
12549  VecFile << PrefDirVector.at(y).ELink << '\n';
12550  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12551  VecFile << PrefDirVector.at(y).XLink << '\n';
12552  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12553  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12554  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12555  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12556  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12557  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12558  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12559  {
12560  VecFile << "************" << '\0' << '\n'; // marker
12561  }
12562  else
12563  {
12564  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12565  }
12566  }
12567  Utilities->CallLogPop(170);
12568 }
12569 
12570 // ---------------------------------------------------------------------------
12571 
12572 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12573 {
12574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12575  int NumberOfSearchElements = SearchVector.size();
12576 
12577  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12578  for(int y = 0; y < NumberOfSearchElements; y++)
12579  {
12580  VecFile << y << '\n'; // extra
12581  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12582  VecFile << SearchVector.at(y).ELink << '\n';
12583  VecFile << SearchVector.at(y).ELinkPos << '\n';
12584  VecFile << SearchVector.at(y).XLink << '\n';
12585  VecFile << SearchVector.at(y).XLinkPos << '\n';
12586  VecFile << SearchVector.at(y).EXNumber << '\n';
12587  VecFile << SearchVector.at(y).CheckCount << '\n';
12588  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12589  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12590  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12591  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12592  {
12593  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12594  }
12595  else
12596  {
12597  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12598  }
12599  }
12600  Utilities->CallLogPop(1847);
12601 }
12602 
12603 // ---------------------------------------------------------------------------
12604 
12605 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12606 /*
12607  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12608  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12609 */
12610 {
12611  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12612  AnsiString(VLoc));
12613  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12614 
12615  if(VecPos > -1)
12616  {
12617  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12618  }
12619  else
12620  {
12621  Utilities->CallLogPop(171);
12622  return;
12623  }
12624  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12625  if(VecPos > -1)
12626  {
12627  ErasePrefDirElementAt(3, VecPos);
12628  }
12629  else
12630  {
12631  Utilities->CallLogPop(172);
12632  return;
12633  }
12634  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12635  if(VecPos > -1)
12636  {
12637  ErasePrefDirElementAt(4, VecPos);
12638  }
12639  else
12640  {
12641  Utilities->CallLogPop(173);
12642  return;
12643  }
12644  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12645  if(VecPos > -1)
12646  {
12647  ErasePrefDirElementAt(5, VecPos);
12648  }
12649  else
12650  {
12651  Utilities->CallLogPop(174);
12652  return;
12653  }
12654  Utilities->CallLogPop(175);
12655 }
12656 
12657 // ---------------------------------------------------------------------------
12658 /*
12659  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12660  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12661 
12662  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12663  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12664  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12665  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12666  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12667  PrefDirVector to correspond to the new track layout.
12668 
12669  {
12670  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12671  if(PrefDirSize() == 0)
12672  {
12673  Utilities->CallLogPop(176);
12674  return;
12675  }
12676  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12677  {
12678  int TV = PrefDirVector.at(x).TrackVectorPosition;
12679  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12680  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12681  if(Track->BlankElementAt(0, TV))
12682  {
12683  ErasePrefDirElementAt(6, x);
12684  }
12685  //if was a blankelement at x then ConnELink and ConnXLink both -1
12686  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12687  {
12688  ErasePrefDirElementAt(7, x);
12689  }
12690  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12691  //needs to be erased once, but if don't use 'else' then will erase two elements
12692  //since 'x' will correspond to the element after the first erased element
12693  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12694  {
12695  ErasePrefDirElementAt(8, x);
12696  }
12697  }
12698  Utilities->CallLogPop(177);
12699  }
12700 */
12701 // ---------------------------------------------------------------------------
12702 
12703 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12704 /*
12705  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12706  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12707 */
12708 {
12709  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12710  bool AlreadyPresent, FoundFlag;
12711  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12712 
12713  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12714  {
12715  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12716  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12717  AlreadyPresent = false;
12718  if(FoundFlag)
12719  {
12720  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12721  {
12722  AlreadyPresent = true;
12723  }
12724  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12725  {
12726  AlreadyPresent = true;
12727  }
12728  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12729  {
12730  AlreadyPresent = true;
12731  }
12732  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12733  {
12734  AlreadyPresent = true;
12735  }
12736  }
12737  if(!AlreadyPresent)
12738  {
12739  StorePrefDirElement(4, TempElement);
12740  }
12741  }
12743  Utilities->CallLogPop(178);
12744 }
12745 /* earlier brute force search
12746  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12747  {
12748  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12749  bool AlreadyPresent = false;
12750  for(unsigned int y = 0;y<PrefDirSize();y++)
12751  {
12752  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12753  }
12754  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12755  }
12756 */
12757 
12758 // ---------------------------------------------------------------------------
12759 
12761 /*
12762  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12763  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12764  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12765  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12766  positions are likely to have changed, so this function is called to reset all the necessary connections and
12767  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12768  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12769  shouldn't have changed.
12770 */
12771 {
12772  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12773  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12774  {
12775  bool FoundFlag;
12776  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12777  if(FoundFlag)
12778  {
12779  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12780  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12781  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12782  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12783  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12784  for(unsigned int z = 0; z < 4; z++)
12785  {
12786  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12787  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12788  }
12789  }
12790  else
12791  {
12792  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12793  }
12794  }
12795  Utilities->CallLogPop(179);
12796 }
12797 
12798 // ---------------------------------------------------------------------------
12799 
12801 /*
12802  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12803 */
12804 {
12805  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12806  bool DiscrepancyFound = false;
12807 
12808  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12809  {
12810  bool FoundFlag;
12811  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12812  if(FoundFlag)
12813  {
12814  TPrefDirElement PE = PrefDirVector.at(x);
12815  if(PE.TrackVectorPosition != VecPos)
12816  {
12817  DiscrepancyFound = true;
12818  break;
12819  }
12820  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12821  {
12822  DiscrepancyFound = true;
12823  break;
12824  }
12825  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12826  {
12827  DiscrepancyFound = true;
12828  break;
12829  }
12830  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
12831  {
12832  DiscrepancyFound = true;
12833  break;
12834  }
12835  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
12836  {
12837  DiscrepancyFound = true;
12838  break;
12839  }
12840  }
12841  else
12842  {
12843  DiscrepancyFound = true;
12844  }
12845  }
12846  if(DiscrepancyFound)
12847  {
12848  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
12849  ClearPrefDir(); // also clears multimap
12850  }
12851  Utilities->CallLogPop(1436);
12852 }
12853 
12854 // ---------------------------------------------------------------------------
12855 
12857 /*
12858  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
12859  return true for OK
12860 */
12861 {
12862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
12863  bool DiscrepancyFound = false;
12864 
12865  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12866  {
12867  bool FoundFlag;
12868  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12869  if(FoundFlag)
12870  {
12871  TPrefDirElement PE = PrefDirVector.at(x);
12872  if(PE.TrackVectorPosition != VecPos)
12873  {
12874  DiscrepancyFound = true;
12875  }
12876  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12877  {
12878  DiscrepancyFound = true;
12879  break;
12880  }
12881  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12882  {
12883  DiscrepancyFound = true;
12884  break;
12885  }
12886  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
12887  {
12888  DiscrepancyFound = true;
12889  break;
12890  }
12891  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
12892  {
12893  DiscrepancyFound = true;
12894  break;
12895  }
12896  }
12897  else
12898  {
12899  DiscrepancyFound = true;
12900  }
12901  }
12902  Utilities->CallLogPop(1512);
12903  return(!DiscrepancyFound);
12904 }
12905 
12906 // ---------------------------------------------------------------------------
12907 
12908 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
12909 /*
12910  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
12911  turn and for the overall sizes.
12912 */
12913 {
12914  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
12915  bool FoundFlag = false;
12916  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
12917 
12918  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
12919  {
12920  TPrefDirElement CheckElement = PrefDirVector.at(a);
12921  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
12922  if(!FoundFlag)
12923  {
12924  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
12925  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
12926  }
12927  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
12928  {
12929  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
12930  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
12931  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
12932  }
12933  }
12934  if(PrefDirVector.size() != PrefDir4MultiMap.size())
12935  {
12936  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
12937  + " Caller=" + (AnsiString)Caller);
12938  }
12939  Utilities->CallLogPop(180);
12940 }
12941 
12942 // ---------------------------------------------------------------------------
12943 
12944 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
12945  int &PrefDirPos3)
12946 /*
12947  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
12948  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
12949  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
12950  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
12951  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
12952 */
12953 {
12954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
12955  AnsiString(VLoc));
12956  THVPair PrefDirMapKeyPair;
12957 
12958  PrefDirPos0 = -1;
12959  PrefDirPos1 = -1;
12960  PrefDirPos2 = -1;
12961  PrefDirPos3 = -1;
12962  FoundFlag = false;
12963  PrefDirMapKeyPair.first = HLoc;
12964  PrefDirMapKeyPair.second = VLoc;
12965  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12966 
12967  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
12968  if(ItPair.first == ItPair.second) //none found
12969  {
12970  Utilities->CallLogPop(181);
12971  return;
12972  }
12973  else
12974  {
12975  FoundFlag = true;
12976  PrefDirPos0 = ItPair.first->second;
12977  ItPair.first++;
12978  if(ItPair.first == ItPair.second)
12979  {
12980  Utilities->CallLogPop(182); //only one found
12981  return;
12982  }
12983  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12984  {
12985  PrefDirPos1 = ItPair.first->second;
12986  }
12987  ItPair.first++;
12988  if(ItPair.first == ItPair.second)
12989  {
12990  Utilities->CallLogPop(183); //2 found
12991  return;
12992  }
12993  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12994  {
12995  PrefDirPos2 = ItPair.first->second;
12996  }
12997  ItPair.first++;
12998  if(ItPair.first == ItPair.second)
12999  {
13000  Utilities->CallLogPop(184); //3 found
13001  return;
13002  }
13003  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13004  {
13005  PrefDirPos3 = ItPair.first->second; //4 found
13006  }
13007  }
13008  Utilities->CallLogPop(185);
13009 }
13010 
13011 // ---------------------------------------------------------------------------
13012 
13013 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13014 { // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13015  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13016  try
13017  {
13018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13019  + "," + AnsiString(LinkNumberPos));
13020  bool FoundFlag;
13021  int PD0, PD1, PD2, PD3;
13022  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13023  {
13024  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13025  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13026  PD0, PD1, PD2, PD3);
13027  if(!FoundFlag)
13028  {
13029  Utilities->CallLogPop(2282);
13030  return(false);
13031  }
13032  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13033  {
13034  if(PD0 > -1)
13035  {
13036  if(PrefDirVector.at(PD0).TrackType == GapJump)//links to a gap and there is a pref dir set on it, doesn't matter about the link position
13037  {
13038  LinkedPrefDirVectorNumber = PD0;
13039  Utilities->CallLogPop(2283);
13040  return(true);
13041  }
13042  }
13043  if(PD1 > -1)
13044  {
13045  if(PrefDirVector.at(PD1).TrackType == GapJump)//can only be PD0 or PD1 for a gap
13046  {
13047  LinkedPrefDirVectorNumber = PD1;
13048  Utilities->CallLogPop(2284);
13049  return(true);
13050  }
13051  }
13052  }
13053  if(PD0 > -1)
13054  {
13055  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13056  {
13057  LinkedPrefDirVectorNumber = PD0;
13058  Utilities->CallLogPop(2285);
13059  return(true);
13060  }
13061  }
13062  if(PD1 > -1)
13063  {
13064  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13065  {
13066  LinkedPrefDirVectorNumber = PD1;
13067  Utilities->CallLogPop(2286);
13068  return(true);
13069  }
13070  }
13071  if(PD2 > -1)
13072  {
13073  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13074  {
13075  LinkedPrefDirVectorNumber = PD2;
13076  Utilities->CallLogPop(2287);
13077  return(true);
13078  }
13079  }
13080  if(PD3 > -1)
13081  {
13082  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13083  {
13084  LinkedPrefDirVectorNumber = PD3;
13085  Utilities->CallLogPop(2288);
13086  return(true);
13087  }
13088  }
13089  LinkedPrefDirVectorNumber = -1;
13090  Utilities->CallLogPop(2289);
13091  return(false);
13092  }
13093  else //buffer or continuation, no link at position 0 but not a failure
13094  {
13095  LinkedPrefDirVectorNumber = -1;
13096  Utilities->CallLogPop(2290);
13097  return(true);
13098  }
13099  }
13100  catch(const Exception &e) //non error catch
13101  {
13102  LinkedPrefDirVectorNumber = -1;
13103  Utilities->CallLogPop(2291);
13104  return(false);
13105  }
13106 }
13107 
13108 // ---------------------------------------------------------------------------
13109 
13111 {
13112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13113  bool FoundFlag; //not used
13114  int PD0, PD1, PD2, PD3;
13115  //recover all PDs at the H & V of PDPtr
13116  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13117 
13118  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13119  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13120 
13121  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13122  {
13123  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13124  {
13125  Utilities->CallLogPop(2292);
13126  return(true);
13127  }
13128  }
13129  if(PD1 > -1)
13130  {
13131  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13132  {
13133  Utilities->CallLogPop(2293);
13134  return(true);
13135  }
13136  }
13137  if(PD2 > -1)
13138  {
13139  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13140  {
13141  Utilities->CallLogPop(2294);
13142  return(true);
13143  }
13144  }
13145  if(PD3 > -1)
13146  {
13147  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13148  {
13149  Utilities->CallLogPop(2295);
13150  return(true);
13151  }
13152  }
13153  Utilities->CallLogPop(2296);
13154  return(false);
13155 }
13156 
13157 // ---------------------------------------------------------------------------
13158 
13159 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13160 /*
13161  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13162 */
13163 {
13164  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13165  PrefDirVector.push_back(LoadPrefDirElement);
13166  THVPair PrefDir4MultiMapKeyPair;
13167  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13168 
13169  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13170  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13171  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13172  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13173  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13174 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13175  Utilities->CallLogPop(186);
13176 }
13177 
13178 // ---------------------------------------------------------------------------
13179 
13180 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13181 /*
13182  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13183  4MultiMap if they are greater than the erased value.
13184 */
13185 {
13186  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13187  bool FoundFlag;
13188 
13189  if(!PrefDirVector.empty())
13190  {
13191  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13192  if(!FoundFlag)
13193  {
13194  throw Exception("Failed to find PrefDir4MultiMap erase element");
13195  }
13196  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13197  PrefDir4MultiMap.erase(EraseIt);
13198  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13200  }
13201  Utilities->CallLogPop(187);
13202 }
13203 
13204 // ---------------------------------------------------------------------------
13205 
13206 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13207 /*
13208  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13209  4MultiMap if they are greater than the erased value.
13210 */
13211 {
13212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13213  AnsiString(ErasedElementNumber));
13214  if(!PrefDir4MultiMap.empty())
13215  {
13216  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13217  {
13218  if(MapPtr->second > ErasedElementNumber)
13219  {
13220  MapPtr->second--;
13221  }
13222  }
13223  }
13224  Utilities->CallLogPop(1450);
13225 }
13226 
13227 // ---------------------------------------------------------------------------
13228 
13229 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13230 /*
13231  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13232  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13233  nothing is found this is an error but the error message is given in the calling function.
13234 */
13235 {
13236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13237  FoundFlag = false;
13238  if(PrefDirVectorPosition >= PrefDirVector.size())
13239  {
13240  throw Exception("PrefDirVectorPosition out of range");
13241  }
13242  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13243  THVPair PrefDir4MultiMapKeyPair;
13244 
13245  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13246  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13247  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13248 
13249  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13250  if(ItPair.first == ItPair.second)
13251  {
13252  Utilities->CallLogPop(188);
13253  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13254  }
13255  else
13256  {
13257  if(ItPair.first->second == PrefDirVectorPosition)
13258  {
13259  FoundFlag = true;
13260  Utilities->CallLogPop(189);
13261  return(ItPair.first);
13262  }
13263  ItPair.first++;
13264  if(ItPair.first == ItPair.second)
13265  {
13266  Utilities->CallLogPop(190);
13267  return(ItPair.first); // nothing found
13268  }
13269  if(ItPair.first->second == PrefDirVectorPosition)
13270  {
13271  FoundFlag = true;
13272  Utilities->CallLogPop(191);
13273  return(ItPair.first);
13274  }
13275  ItPair.first++;
13276  if(ItPair.first == ItPair.second)
13277  {
13278  Utilities->CallLogPop(192);
13279  return(ItPair.first); // nothing found
13280  }
13281  if(ItPair.first->second == PrefDirVectorPosition)
13282  {
13283  FoundFlag = true;
13284  Utilities->CallLogPop(193);
13285  return(ItPair.first);
13286  }
13287  ItPair.first++;
13288  if(ItPair.first == ItPair.second)
13289  {
13290  Utilities->CallLogPop(194);
13291  return(ItPair.first); // nothing found
13292  }
13293  if(ItPair.first->second == PrefDirVectorPosition)
13294  {
13295  FoundFlag = true;
13296  Utilities->CallLogPop(195);
13297  return(ItPair.first);
13298  }
13299  }
13300  Utilities->CallLogPop(196);
13301  return(ItPair.first); // nothing found
13302 }
13303 
13304 // ---------------------------------------------------------------------------
13305 
13306 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13307 /*
13308  Although there may be up to four entries at one H & V position this function gets just one. It is
13309  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13310  at H & V.
13311 */
13312 {
13313  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13314  THVPair PrefDir4MultiMapKeyPair;
13315 
13316  PrefDir4MultiMapKeyPair.first = HLoc;
13317  PrefDir4MultiMapKeyPair.second = VLoc;
13318  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13319 
13320  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13321  if(ItPair.first == ItPair.second) // nothing found
13322  {
13323  Utilities->CallLogPop(197);
13324  return(-1);
13325  }
13326  else
13327  {
13328  Utilities->CallLogPop(198);
13329  return(ItPair.first->second);
13330  }
13331 }
13332 
13333 // ---------------------------------------------------------------------------
13334 
13335 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13336 {
13337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13338  bool ErasedFlag = false;
13339 
13340  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13341  {
13342  if(PrefDirSize() == 0)
13343  {
13344  Utilities->CallLogPop(1511);
13345  return;
13346  }
13347  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13348  {
13349  ErasedFlag = false;
13350  // use 'else' to ensure don't try to access an erased element
13351  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13352  {
13353  ErasePrefDirElementAt(11, x);
13354  ErasedFlag = true;
13355  }
13356  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13357  {
13358  ErasePrefDirElementAt(12, x);
13359  ErasedFlag = true;
13360  }
13361  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13362  {
13363  ErasePrefDirElementAt(13, x);
13364  ErasedFlag = true;
13365  }
13366  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13367  {
13368  ErasePrefDirElementAt(9, x);
13369  ErasedFlag = true;
13370  }
13371  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13372  {
13373  ErasePrefDirElementAt(10, x);
13374  ErasedFlag = true;
13375  }
13376  if(!ErasedFlag)
13377  {
13378  // don't use 'else' here as may be more than one that need decrementing
13379  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13380  {
13381  PrefDirVector.at(x).TrackVectorPosition--;
13382  }
13383  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13384  {
13385  PrefDirVector.at(x).Conn[0]--;
13386  }
13387  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13388  {
13389  PrefDirVector.at(x).Conn[1]--;
13390  }
13391  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13392  {
13393  PrefDirVector.at(x).Conn[2]--;
13394  }
13395  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13396  {
13397  PrefDirVector.at(x).Conn[3]--;
13398  }
13399  }
13400  }
13401  }
13402  Utilities->CallLogPop(1434);
13403 }
13404 
13405 // ---------------------------------------------------------------------------
13406 
13407 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13408 {
13409  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13410  OverallDistance = 0;
13411  OverallSpeedLimit = 0;
13412  LeadingPointsAtLastElement = false;
13413  if(PrefDirSize() == 0) // shouldn't be empty when this called
13414  {
13415  Utilities->CallLogPop(1491);
13416  return;
13417  }
13418  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13419  {
13420  LeadingPointsAtLastElement = true;
13421  Utilities->CallLogPop(1492);
13422  return;
13423  }
13424  for(unsigned int x = 0; x < PrefDirSize(); x++)
13425  {
13426  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13427  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13428  {
13429  OverallDistance += PrefDirElement.Length23;
13430  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13431  {
13432  if(x == 0)
13433  {
13434  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13435  }
13436  else
13437  {
13438  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13439  {
13440  OverallSpeedLimit = -1;
13441  }
13442  }
13443  }
13444  }
13445  else
13446  {
13447  OverallDistance += PrefDirElement.Length01;
13448  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13449  {
13450  if(x == 0)
13451  {
13452  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13453  }
13454  else
13455  {
13456  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13457  {
13458  OverallSpeedLimit = -1;
13459  }
13460  }
13461  }
13462  }
13463  }
13464  Utilities->CallLogPop(1529);
13465 }
13466 
13467 // ---------------------------------------------------------------------------
13468 
13469 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13470 {
13471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13472  if(PrefDirSize() == 0)
13473  {
13474  Utilities->CallLogPop(1564);
13475  return;
13476  }
13477  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13478  bool FoundFlag;
13480  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13481 
13482  while(MMIT != PrefDir4MultiMap.end())
13483  {
13484  HLoc = MMIT->first.first;
13485  VLoc = MMIT->first.second;
13486  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13487  H = HLoc - Track->GetHLocMin();
13488  V = VLoc - Track->GetVLocMin();
13489  // always found in order, any missing have PrefDirPosx == -1
13490  if(PrefDirPos0 > -1)
13491  {
13492  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13493  }
13494  if(PrefDirPos1 > -1)
13495  {
13496  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13497  }
13498  if(PrefDirPos2 > -1)
13499  {
13500  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13501  }
13502  if(PrefDirPos3 > -1)
13503  {
13504  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13505  }
13506  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13507  {
13508  // need to plot all 4 in order to obtain all the direction graphics
13509  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13510  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13511  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13512  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13513  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13514  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13515  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13516  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13517  MMIT++;
13518  MMIT++;
13519  MMIT++;
13520  MMIT++;
13521  }
13522  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13523  {
13524  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13525  {
13526  // 0 & 1 constitute the bidirectional PrefDir
13527  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13528  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13529  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13530  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13531  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13532  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13533  MMIT++;
13534  MMIT++;
13535  MMIT++;
13536  }
13537  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13538  {
13539  // 0 & 2 constitute the bidirectional PrefDir
13540  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13541  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13542  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13543  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13544  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13545  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13546  MMIT++;
13547  MMIT++;
13548  MMIT++;
13549  }
13550  else
13551  {
13552  // 1 & 2 constitute the bidirectional PrefDir
13553  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13554  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13555  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13556  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13557  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13558  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13559  MMIT++;
13560  MMIT++;
13561  MMIT++;
13562  }
13563  }
13564  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13565  {
13566  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13567  {
13568  // 0 & 1 constitute the bidirectional PrefDir
13569  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13570  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13571  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13572  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13573  MMIT++;
13574  MMIT++;
13575  }
13576  else
13577  {
13578  // 2 unidirectional PrefDirs
13579  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13580  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13581  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13582  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13583  MMIT++;
13584  MMIT++;
13585  }
13586  }
13587  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13588  {
13589  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13590  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13591  MMIT++;
13592  }
13593  }
13594  Utilities->CallLogPop(1565);
13595 }
13596 
13597 // ---------------------------------------------------------------------------
13598 
13599 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13600 /*
13601  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13602  level crossing, signals with wrong direction set, or buffers.
13603 */
13604 {
13605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13606  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13607  bool FoundFlag;
13609  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13610 
13611  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13612  ElementIn.VLoc)))
13613  {
13614  Utilities->CallLogPop(1982);
13615  return(false);
13616  }
13617  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13618  {
13619  Utilities->CallLogPop(1983);
13620  return(false);
13621  }
13622  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13623  {
13624  Utilities->CallLogPop(1995);
13625  return(false);
13626  }
13627 // Now check that there is only a single prefdir set
13628  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13629 // always found in order, any missing have PrefDirPosx == -1
13630  if(PrefDirPos0 > -1)
13631  {
13632  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13633  }
13634  if(PrefDirPos1 > -1)
13635  {
13636  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13637  }
13638  if(PrefDirPos2 > -1)
13639  {
13640  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13641  }
13642  if(PrefDirPos3 > -1)
13643  {
13644  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13645  }
13646  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13647  {
13648  Utilities->CallLogPop(1984);
13649  return(false);
13650  }
13651  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13652  {
13653  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13654  {
13655  Utilities->CallLogPop(1985);
13656  return(false);
13657  }
13658  else
13659  {
13660  Utilities->CallLogPop(1986);
13661  return(true);
13662  }
13663  }
13664  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13665  {
13666  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13667  {
13668  Utilities->CallLogPop(1987);
13669  return(false);
13670  }
13671  else
13672  {
13673  Utilities->CallLogPop(1988);
13674  return(true);
13675  }
13676  }
13677  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13678  {
13679  if(PrefDirElement0.XLinkPos == EntryPos)
13680  {
13681  Utilities->CallLogPop(1989);
13682  return(false);
13683  }
13684  else
13685  {
13686  Utilities->CallLogPop(1990);
13687  return(true);
13688  }
13689  }
13690  else
13691  {
13692  Utilities->CallLogPop(1991);
13693  return(false); // none found
13694  }
13695 }
13696 
13697 // ---------------------------------------------------------------------------
13698 
13700 {
13701 /* //Added at v2.1.0
13702  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13703  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13704  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13705  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13706  and can be modelled better anyway.
13707 
13708  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13709  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13710  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13711  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13712  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13713  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13714 */
13715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13716  ElementIn.VLoc + "," + XLink);
13717  int TrackVecPos;
13718  bool TrackFoundFlag;
13719  TTrackElement TempTrackElement;
13720 
13721  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13722  {
13723  Utilities->CallLogPop(2047);
13724  return(false);
13725  }
13726 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13727  if(XLink == 1)
13728  {
13729  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13730  if(TrackFoundFlag)
13731  {
13732  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13733  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13734  {
13735  Utilities->CallLogPop(2048);
13736  return(true);
13737  }
13738  }
13739  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13740  if(TrackFoundFlag)
13741  {
13742  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13743  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13744  {
13745  Utilities->CallLogPop(2049);
13746  return(true);
13747  }
13748  }
13749  }
13750 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13751  if(XLink == 3)
13752  {
13753  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13754  if(TrackFoundFlag)
13755  {
13756  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13757  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13758  {
13759  Utilities->CallLogPop(2050);
13760  return(true);
13761  }
13762  }
13763  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13764  if(TrackFoundFlag)
13765  {
13766  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13767  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13768  {
13769  Utilities->CallLogPop(2051);
13770  return(true);
13771  }
13772  }
13773  }
13774 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13775  if(XLink == 7)
13776  {
13777  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13778  if(TrackFoundFlag)
13779  {
13780  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13781  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13782  {
13783  Utilities->CallLogPop(2052);
13784  return(true);
13785  }
13786  }
13787  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13788  if(TrackFoundFlag)
13789  {
13790  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13791  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13792  {
13793  Utilities->CallLogPop(2053);
13794  return(true);
13795  }
13796  }
13797  }
13798 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13799  if(XLink == 9)
13800  {
13801  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13802  if(TrackFoundFlag)
13803  {
13804  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13805  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13806  {
13807  Utilities->CallLogPop(2054);
13808  return(true);
13809  }
13810  }
13811  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13812  if(TrackFoundFlag)
13813  {
13814  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13815  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13816  {
13817  Utilities->CallLogPop(2055);
13818  return(true);
13819  }
13820  }
13821  }
13822  Utilities->CallLogPop(2056);
13823  return(false);
13824 }
13825 
13826 // ---------------------------------------------------------------------------
13827 
13828 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
13829 {
13830 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
13831  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
13832  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
13833  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
13834  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
13835 */
13836  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
13838  bool FoundFlag, ContFlag, FoundElements = false;
13839  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13840  TPrefDirElement NextElement;
13841 
13842  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
13843  {
13844  LastIteratorValue++;
13845  ContFlag = false;
13846  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
13847  {
13848  continue;
13849  }
13850  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
13851  {
13852  continue;
13853  }
13854 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
13855  // found a potential route start point
13856  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
13857  {
13858  continue;
13859  }
13860  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
13861  {
13862  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
13863  if(PDVIt->TrackType == Continuation)
13864  {
13865  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
13866  {
13867  continue;
13868  }
13869  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
13870  {
13871  continue;
13872  }
13873  }
13874  StartElement = *PDVIt;
13875 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
13876  // diverging track on which there was no pref dir. See below for 2 required changes.
13877  }
13878  else
13879  {
13880  continue;
13881  }
13882  // now track along until find a signal or continuation, checking validity for each element
13883  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
13884  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
13885  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13886  if(PrefDirPos0 == -1) // no continuing prefdir
13887  {
13888  continue;
13889  }
13890  bool NextElementFoundFlag = false;
13891  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13892  {
13893  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
13894  NextElementFoundFlag = true;
13895  }
13896  if(PrefDirPos1 > -1)
13897  {
13898  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13899  {
13900  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
13901  NextElementFoundFlag = true;
13902  }
13903  }
13904  if(PrefDirPos2 > -1)
13905  {
13906  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13907  {
13908  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
13909  NextElementFoundFlag = true;
13910  }
13911  }
13912  if(PrefDirPos3 > -1)
13913  {
13914  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13915  {
13916  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
13917  NextElementFoundFlag = true;
13918  }
13919  }
13920  if(!NextElementFoundFlag)
13921  {
13922  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
13923 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
13924  }
13925  while(true)
13926  {
13927  // check validity
13928  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
13929  {
13930  ContFlag = true;
13931  break;
13932  }
13933  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
13934  {
13935  ContFlag = true;
13936  break;
13937  }
13938  // check if in a route, providing not a signal, as a signal might be at the start of a route
13939  if(NextElement.TrackType != SignalPost)
13940  {
13941  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
13942  {
13943  ContFlag = true;
13944  break;
13945  }
13946  }
13947  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
13948  // can't be a gound signal as would have failed the validity test
13949  {
13950  EndElement = NextElement;
13951  break;
13952  }
13953  // get the next element in the sequence
13954  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
13955  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
13956  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13957  if(PrefDirPos0 == -1) // no continuing prefdir
13958  {
13959  ContFlag = true;
13960  break;
13961  }
13962  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13963  {
13964  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
13965  continue;
13966  }
13967  if(PrefDirPos1 > -1)
13968  {
13969  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13970  {
13971  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
13972  continue;
13973  }
13974  }
13975  if(PrefDirPos2 > -1)
13976  {
13977  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13978  {
13979  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
13980  continue;
13981  }
13982  }
13983  if(PrefDirPos3 > -1)
13984  {
13985  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13986  {
13987  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
13988  continue;
13989  }
13990  }
13991  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
13992  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
13993  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
13994  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
13995  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
13996  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
13997  {
13998  ContFlag = true;
13999  break;
14000  }
14001  else
14002  {
14003  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14004  // could drop the bridge test but keep it to show the change history
14005  break;
14006 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14007  }
14008  }
14009  if(ContFlag)
14010  {
14011  continue;
14012  }
14013  // else have start and end elements set & all elements valid, so set up the route segment
14014  FoundElements = true;
14015  break;
14016  }
14017  if(FoundElements)
14018  {
14019  Utilities->CallLogPop(1992);
14020  return(true);
14021  }
14022  else
14023  {
14024  Utilities->CallLogPop(1993);
14025  return(false);
14026  }
14027 }
14028 
14029 // ---------------------------------------------------------------------------
14030 // TOneRoute
14031 // ---------------------------------------------------------------------------
14032 
14033 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14034 {
14035 /* General:
14036  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14037  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14038  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14039  route will use automatic signals or not.
14040  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14041  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14042  elements, so additional work is needed to complete all their members before they are ready for conversion into
14043  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14044  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14045  ConvertAndAdd.......
14046 */
14047  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14048  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14049  ClearRoute();
14050  int TrackVectorPosition;
14051  TTrackElement TrackElement;
14052  TPrefDirElement FirstElement, LastElement;
14053 
14054  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14055  {
14056  Utilities->CallLogPop(199);
14057  return(false);
14058  }
14059  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14060  {
14061  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14062  Utilities->CallLogPop(1996);
14063  return(false);
14064  }
14065  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14066  {
14067  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14068  Utilities->CallLogPop(200);
14069  return(false);
14070  }
14071  if(Track->IsLCAtHV(18, HLoc, VLoc))
14072  {
14073  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14074  Utilities->CallLogPop(1909);
14075  return(false);
14076  }
14077 // check if selected a train & disallow if so
14078  if(TrackElement.TrainIDOnElement > -1)
14079  {
14080  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14081  Utilities->CallLogPop(202);
14082  return(false);
14083  }
14084 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14085  TPrefDirElement PrefDirElement;
14086  int LockedVectorNumber;
14087 
14088  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14089  {
14090  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14091  Utilities->CallLogPop(203);
14092  return(false);
14093  }
14094  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14095  {
14096  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14097  Utilities->CallLogPop(204);
14098  return(false);
14099  }
14101  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14102 // signal in an autosig route & follow with a non-autosig route
14103 
14104  TPrefDirElement BlankElement;
14105 
14106  StartElement1 = BlankElement;
14107  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14108 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14109  bool InPrefDirFlag = false;
14110 
14111  bool FoundFlag;
14112  int PrefDirPos0 = -1;
14113  int PrefDirPos1 = -1;
14114  int PrefDirPos2 = -1;
14115  int PrefDirPos3 = -1;
14116 
14118  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14119  int PrefDirVecPos[4] =
14120  {
14121  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14122  };
14123 
14124  for(int x = 0; x < 4; x++)
14125  {
14126  int b = PrefDirVecPos[x];
14127  if(b > -1)
14128  {
14129  // only allow the appropriate exit route to be searched
14130  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14131  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14132  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14133  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14134  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14135  {
14136  InPrefDirFlag = true;
14137  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14138  if(AutoSigsFlag)
14139  {
14140  StartElement1.AutoSignals = true;
14141  }
14142  StartElement1.PrefDirRoute = true;
14143  }
14144  }
14145  }
14146 
14147  if(!InPrefDirFlag)
14148  {
14150  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14151  Utilities->CallLogPop(205);
14152  return(false);
14153  }
14154 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14156  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14157 
14158  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14159  {
14160  throw Exception("Selection in two routes - should never happen!");
14161  }
14162  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14163  {
14164  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14165  {
14166  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14167  Utilities->CallLogPop(206);
14168  return(false);
14169  }
14170  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14171  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14172  {
14173  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14174  Utilities->CallLogPop(207);
14175  return(false);
14176  }
14177  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14178  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14179  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14180  {
14181  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14182  Utilities->CallLogPop(208);
14183  return(false);
14184  }
14185  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14187  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14188  if(AutoSigsFlag)
14189  {
14190  StartElement1.AutoSignals = true;
14191  }
14192  StartElement1.PrefDirRoute = true;
14194  Utilities->CallLogPop(209);
14195  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14196  }
14197 
14198  else // no route started
14199  {
14200 // check if selected position is adjacent to start or end of an existing route and disallow
14201  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14202  {
14203  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14204  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14205  {
14206  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14207  Utilities->CallLogPop(210);
14208  return(false);
14209  }
14210  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14211  {
14212  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14213  Utilities->CallLogPop(211);
14214  return(false);
14215  }
14216  }
14217 
14218 // check if it's adjacent to end of an an existing route,
14219  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14220  {
14222  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14223  {
14224  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14225  Utilities->CallLogPop(212);
14226  return(false);
14227  }
14228  }
14229  SearchVector.push_back(StartElement1);
14230  Utilities->CallLogPop(213);
14231  return(true);
14232  }
14233 }
14234 
14235 // ---------------------------------------------------------------------------
14236 
14237 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14238  IDInt &ReqPosRouteID, bool &PointsChanged)
14239 
14240 /*
14241  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14242 
14243  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14244  this being set to -1 for not used.
14245  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14246  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14247  Check correct type of element - signal/buffers/continuation.
14248  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14249  EndElement2 corresponding to the 2 possible PrefDir elements).
14250  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14251  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14252  linked forward to another route.
14253  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14254  for same position as start should cover this)
14255 
14256  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14257  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14258  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14259  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14260  If the search fails then return false.
14261  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14262  in the SearchVector to ensure it's entered as part of the new route.
14263  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14264  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14265  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14266  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14267  so return false, with an appropriate message if ConsecSignalsRoute set.
14268 */
14269 
14270 {
14271  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14272  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14273  int EndPosition; // the position selected
14274 
14275  Track->LCFoundInAutoSigsRoute = false;
14277  TotalSearchCount = 0;
14278  ReqPosRouteID = IDInt(-1); // default value for not used
14279  TTrackElement TrackElement;
14280  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14281  // given element as can't select 2-track elements
14282  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14283  {
14284  Utilities->CallLogPop(214);
14285  return(false);
14286  }
14287  if(Track->IsLCAtHV(19, HLoc, VLoc))
14288  {
14289  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14290  Utilities->CallLogPop(1908);
14291  return(false);
14292  }
14293 // cancel selection if on original start element
14294  if(EndPosition == StartRoutePosition)
14295  {
14296  Utilities->CallLogPop(215);
14297  return(false);
14298  }
14299  if(AutoSigsFlag)
14300  {
14301  if(TrackElement.TrackType == Buffers)
14302  {
14303  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14304  Utilities->CallLogPop(216);
14305  return(false);
14306  }
14307  }
14308  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14309  {
14310  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14311  Utilities->CallLogPop(217);
14312  return(false);
14313  }
14314 // check if train on element
14315  if(TrackElement.TrainIDOnElement > -1)
14316  {
14317  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14318  Utilities->CallLogPop(219);
14319  return(false);
14320  }
14321 // disallow if not in EveryPrefDir & set EndElement(s)
14322  bool InPrefDirFlag = false;
14323 
14324  bool FoundFlag;
14325  int PrefDirPos0 = -1;
14326  int PrefDirPos1 = -1;
14327  int PrefDirPos2 = -1;
14328  int PrefDirPos3 = -1;
14329 
14330  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14331  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14332  int PrefDirVecPos[4] =
14333  {
14334  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14335  };
14336 
14337  for(int x = 0; x < 4; x++)
14338  {
14339  int b = PrefDirVecPos[x];
14340  if(b > -1)
14341  {
14342  InPrefDirFlag = true;
14343  if(EndElement1.TrackVectorPosition == -1)
14344  {
14345  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14346  }
14347  else
14348  {
14349  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14350  }
14351  }
14352  }
14353  if(!InPrefDirFlag)
14354  {
14356  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14357  Utilities->CallLogPop(220);
14358  return(false);
14359  }
14360 // check if in an existing route - can't be a bridge so can use a simple 'find'
14361 // bool InRoute = false;
14363  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14364 
14365  if(RoutePair.first > -1)
14366  {
14367  if(RoutePair.second != 0) // not first element in existing route so no good
14368  {
14369  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14370  Utilities->CallLogPop(221);
14371  return(false);
14372  }
14373  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14374 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14375  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14376  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14377  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14378  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14379  {
14380  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14381  Utilities->CallLogPop(222);
14382  return(false);
14383  }
14384  EndElement1 = RouteElement;
14385  EndElement2 = BlankElement; // only need the route element
14386  EndPosition = EndElement1.TrackVectorPosition;
14387  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14388  }
14389 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14390 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14391 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14392 
14393  if(EndElement1.HLoc >= StartElement1.HLoc)
14394  {
14396  SearchLimitHighH = EndElement1.HLoc + 15;
14397  }
14398  else
14399  {
14400  SearchLimitLowH = EndElement1.HLoc - 15;
14402  }
14403  if(EndElement1.VLoc >= StartElement1.VLoc)
14404  {
14406  SearchLimitHighV = EndElement1.VLoc + 15;
14407  }
14408  else
14409  {
14410  SearchLimitLowV = EndElement1.VLoc - 15;
14412  }
14413 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14414  check & TotalSearchCounts check
14415  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14416  {
14417  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14418  Utilities->CallLogPop(1693);
14419  return false;
14420  }
14421 */
14422 // check if adjacent to start and disallow
14423  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14424  {
14426  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14427 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14428 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14429  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14430  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14431  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14432  {
14433  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14434  Utilities->CallLogPop(223);
14435  return(false);
14436  }
14437 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14438 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14439  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14440  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14441  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14442  {
14443  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14444  Utilities->CallLogPop(224);
14445  return(false);
14446  }
14447 // check if adjacent to end of a route & disallow
14449  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14450  {
14451  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14452  Utilities->CallLogPop(225);
14453  return(false);
14454  }
14455  }
14456 
14457 // check for same route as start element
14459  {
14460  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14461  Utilities->CallLogPop(226);
14462  return(false);
14463  }
14464 // check for a looping route
14465  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14466  {
14468  {
14469  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14470  Utilities->CallLogPop(1844);
14471  return(false);
14472  }
14473  }
14474 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14475 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14476 // and don't want to add it again
14477  if(StartSelectionRouteID > -1)
14478  {
14479  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14480  AutoSigsFlag))
14481  {
14482  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14483  if(PointsToBeChanged(5))
14484  {
14485  PointsChanged = true;
14486  }
14487  Utilities->CallLogPop(227);
14488  return(true);
14489  }
14490  else if(!Track->SuppressRouteFailMessage)
14491  {
14492  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14494  Utilities->CallLogPop(228);
14495  return(false);
14496  }
14497  }
14498  else
14499  {
14500 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14501 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14502 
14503 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14504 // note that a blank element will have XLinkPos set to -1
14505  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14506  {
14507  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14508  AutoSigsFlag))
14509  {
14510  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14511  if(PointsToBeChanged(6))
14512  {
14513  PointsChanged = true;
14514  }
14515  Utilities->CallLogPop(229);
14516  return(true);
14517  }
14518  else
14519  {
14521  {
14523  }
14524  Utilities->CallLogPop(230);
14525  return(false);
14526  }
14527  }
14528  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14529  {
14530  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14531  AutoSigsFlag))
14532  {
14533  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14534  if(PointsToBeChanged(7))
14535  {
14536  PointsChanged = true;
14537  }
14538  Utilities->CallLogPop(231);
14539  return(true);
14540  }
14541  else
14542  {
14544  {
14546  }
14547  Utilities->CallLogPop(232);
14548  return(false);
14549  }
14550  }
14551  // now start off in the best direction
14552  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14553  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14554  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14555  // unless new problems are found.
14556  if(StartElement1.XLinkPos == BestPos)
14557  {
14558  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14559  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14560  AutoSigsFlag))
14561  {
14562  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14563  if(PointsToBeChanged(8))
14564  {
14565  PointsChanged = true;
14566  }
14567  Utilities->CallLogPop(233);
14568  return(true);
14569  }
14570  else if(StartElement2.TrackVectorPosition > -1)
14571  {
14572  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14573  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14574  AutoSigsFlag))
14575  {
14576  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14577  if(PointsToBeChanged(9))
14578  {
14579  PointsChanged = true;
14580  }
14581  Utilities->CallLogPop(234);
14582  return(true);
14583  }
14584  }
14585  }
14586  else if(StartElement2.TrackVectorPosition > -1)
14587  {
14588  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14589  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14590  AutoSigsFlag))
14591  {
14592  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14593  if(PointsToBeChanged(10))
14594  {
14595  ;
14596  }
14597  {
14598  PointsChanged = true;
14599  }
14600  Utilities->CallLogPop(1857);
14601  return(true);
14602  }
14603  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14604  AutoSigsFlag))
14605  {
14606  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14607  if(PointsToBeChanged(11))
14608  {
14609  ;
14610  }
14611  {
14612  PointsChanged = true;
14613  }
14614  Utilities->CallLogPop(1858);
14615  return(true);
14616  }
14617  }
14618  else if(StartElement1.XLinkPos == (1 - BestPos))
14619  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14620  {
14621  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14622  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14623  AutoSigsFlag))
14624  {
14625  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14626  if(PointsToBeChanged(12))
14627  {
14628  PointsChanged = true;
14629  }
14630  Utilities->CallLogPop(1864);
14631  return(true);
14632  }
14633  }
14634  }
14636  {
14638  }
14639  Utilities->CallLogPop(235);
14640  return(false);
14641 }
14642 
14643 // ---------------------------------------------------------------------------
14644 
14645 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14646 {
14647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14648  if(PrefDirSize() == 0)
14649  {
14650  Utilities->CallLogPop(1704);
14651  return;
14652  }
14653  for(unsigned int x = 0; x < PrefDirSize(); x++)
14654  {
14655  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14656  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14657  {
14658  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14659  TempPrefDirElement.EXGraphicPtr);
14660  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14661  {
14662  if(x == 0)
14663  {
14664  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14665  TempPrefDirElement.EntryDirectionGraphicPtr);
14666  }
14667  if(x == (PrefDirSize() - 1))
14668  {
14669  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14670  TempPrefDirElement.EntryDirectionGraphicPtr);
14671  }
14672  }
14673  }
14674  }
14675 
14676  Utilities->CallLogPop(1705);
14677 }
14678 
14679 // ---------------------------------------------------------------------------
14680 
14681 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14682  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14683 
14684 /*
14685  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14686  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14687  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14688  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14689  Return false if any element (apart from RequiredPosition) is on an existing route.
14690  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14691 
14692  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14693  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14694  added during the function so as to leave it exactly as it was on entering, then return false).
14695  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14696  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14697  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14698  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14699  the route number that the searched-for element is the start of if any, and set to -1 if no
14700  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14701  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14702  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14703  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14704 
14705  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14706  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14707  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14708  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14709  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14710  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14711  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14712  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14713  or if train on element (unless a bridge & train on different track).
14714  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14715  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14716  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14717  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14718  AutoSignals member set if AutoSigsFlag set, then return true.
14719  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14720 
14721  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14722  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14723  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14724  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14725  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14726  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14727  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14728 
14729  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14730  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14731 */
14732 
14733 {
14734  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14735  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14736  AnsiString((short)AutoSigsFlag));
14737  int VectorCount = 0;
14738  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14739 
14740 // check for a fouled diagonal for first element. Added for v1.3.2
14741  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14742  {
14743  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14744  {
14745  for(int x = 0; x < VectorCount; x++)
14746  {
14747  SearchVector.erase(SearchVector.end() - 1);
14748  }
14749  Utilities->CallLogPop(2043);
14750  return(false);
14751  }
14752  }
14753  bool FirstPass = true;
14754 
14755  while(true)
14756  {
14757  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14758  {
14759  Track->LCFoundInAutoSigsRoute = true;
14760  }
14761  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14762  {
14763  for(int x = 0; x < VectorCount; x++)
14764  {
14765  SearchVector.erase(SearchVector.end() - 1);
14766  }
14767  Utilities->CallLogPop(1926);
14768  return(false);
14769  }
14770  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14771  {
14772  for(int x = 0; x < VectorCount; x++)
14773  {
14774  SearchVector.erase(SearchVector.end() - 1);
14775  }
14776  Utilities->CallLogPop(236);
14777  return(false);
14778  }
14779  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14780  // reached a valid signal that isn't the required position, user should always select the next
14781  // signal in a route so have to fail
14782  // won't affect recurive searches as for them the first pass element is always a point
14783  {
14784  for(int x = 0; x < VectorCount; x++)
14785  {
14786  SearchVector.erase(SearchVector.end() - 1);
14787  }
14788  Utilities->CallLogPop(237);
14789  return(false);
14790  }
14791  FirstPass = false;
14792  int NextPosition = PrefDirElement.Conn[XLinkPos];
14793  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14794  TPrefDirElement SearchElement(NextTrackElement);
14795  SearchElement.TrackVectorPosition = NextPosition;
14796  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14797  SearchElement.ELinkPos = NextELinkPos;
14798  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14799  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14800  int NextXLinkPos;
14801  if(SearchElement.ELinkPos == 0)
14802  {
14803  NextXLinkPos = 1;
14804  }
14805  if(SearchElement.ELinkPos == 1)
14806  {
14807  NextXLinkPos = 0;
14808  }
14809  if(SearchElement.ELinkPos == 2)
14810  {
14811  NextXLinkPos = 3;
14812  }
14813  if(SearchElement.ELinkPos == 3)
14814  {
14815  NextXLinkPos = 2;
14816  }
14817  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14818  {
14819  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14820 // note that may be buffers, continuation or gap
14821  SearchElement.XLinkPos = NextXLinkPos;
14822  }
14823 // can't set XLink or XLinkPos yet if the element is a leading point.
14824 
14825 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14826  for(unsigned int x = 0; x < SearchVector.size(); x++)
14827  {
14828  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14829  {
14830  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14831  // OK if a bridge & routes on different tracks
14832  {
14833  for(int x = 0; x < VectorCount; x++)
14834  {
14835  SearchVector.erase(SearchVector.end() - 1);
14836  }
14837  Utilities->CallLogPop(238);
14838  return(false);
14839  }
14840  }
14841  }
14842 
14843 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14844  TAllRoutes::TRouteElementPair SecondPair;
14846  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14847  if(RoutePair.first > -1)
14848  {
14849  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14850  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
14851  RoutePair.second).ELinkPos)))
14852  {
14853  // still OK if start of an expected route
14854  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
14855  {
14856  for(int x = 0; x < VectorCount; x++)
14857  {
14858  SearchVector.erase(SearchVector.end() - 1);
14859  }
14860  Utilities->CallLogPop(239);
14861  return(false); // only allow for start of an expected route
14862  }
14863  }
14864  }
14865  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14866  {
14867  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14868  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
14869  SecondPair.second).ELinkPos)))
14870  {
14871  // still OK if start of an expected route
14872  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
14873  {
14874  for(int x = 0; x < VectorCount; x++)
14875  {
14876  SearchVector.erase(SearchVector.end() - 1);
14877  }
14878  Utilities->CallLogPop(240);
14879  return(false); // only allow for start of an expected route
14880  }
14881  }
14882  }
14883 // check if a train on element, unless a bridge & train on different track
14884 // OK of same train as start element - no drop this
14885 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14886  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14887  {
14888  for(int x = 0; x < VectorCount; x++)
14889  {
14890  SearchVector.erase(SearchVector.end() - 1);
14891  }
14892  Utilities->CallLogPop(241);
14893  return(false);
14894  }
14895  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14896  {
14897  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14898  {
14899  for(int x = 0; x < VectorCount; x++)
14900  {
14901  SearchVector.erase(SearchVector.end() - 1);
14902  }
14903  Utilities->CallLogPop(242);
14904  return(false);
14905  }
14906  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14907  {
14908  for(int x = 0; x < VectorCount; x++)
14909  {
14910  SearchVector.erase(SearchVector.end() - 1);
14911  }
14912  Utilities->CallLogPop(243);
14913  return(false);
14914  }
14915  }
14916 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
14917  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14918  {
14919  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14920  {
14921  for(int x = 0; x < VectorCount; x++)
14922  {
14923  SearchVector.erase(SearchVector.end() - 1);
14924  }
14925  Utilities->CallLogPop(244);
14926  return(false);
14927  }
14928  }
14929 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
14930 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
14931  bool InPrefDirFlag = false;
14932  PrefDirElement1 = BlankElement;
14933  PrefDirElement2 = BlankElement;
14934 
14935  bool FoundFlag;
14936  int PrefDirPos0 = -1;
14937  int PrefDirPos1 = -1;
14938  int PrefDirPos2 = -1;
14939  int PrefDirPos3 = -1;
14941  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14942  int PrefDirVecPos[4] =
14943  {
14944  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14945  };
14946  for(int x = 0; x < 4; x++)
14947  {
14948  int b = PrefDirVecPos[x];
14949  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
14950  {
14951  InPrefDirFlag = true;
14952  if(PrefDirElement1.TrackVectorPosition == -1)
14953  {
14954  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
14955  }
14956  else
14957  {
14958  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
14959  }
14960  }
14961  }
14962  if(!InPrefDirFlag)
14963  {
14964  for(int x = 0; x < VectorCount; x++)
14965  {
14966  SearchVector.erase(SearchVector.end() - 1);
14967  }
14968  Utilities->CallLogPop(245);
14969  return(false);
14970  }
14971 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14972 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14973 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14975  {
14976  for(int x = 0; x < VectorCount; x++)
14977  {
14978  SearchVector.erase(SearchVector.end() - 1);
14979  }
14980  Utilities->CallLogPop(1690);
14981  return(false);
14982  }
14983 // check if found it
14984  if(SearchElement.TrackVectorPosition == RequiredPosition)
14985  {
14986 // need to ensure a signal/buffer/continuation
14987  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
14988  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
14989  {
14990  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
14992  for(int x = 0; x < VectorCount; x++)
14993  {
14994  SearchVector.erase(SearchVector.end() - 1);
14995  }
14996  Utilities->CallLogPop(246);
14997  return(false);
14998  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
14999 
15000  if(AutoSigsFlag)
15001  {
15002  PrefDirElement1.AutoSignals = true;
15003  }
15004  PrefDirElement1.PrefDirRoute = true;
15006  {
15008  {
15009  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15011  }
15012  for(int x = 0; x < VectorCount; x++)
15013  {
15014  SearchVector.erase(SearchVector.end() - 1);
15015  }
15016  Utilities->CallLogPop(1928);
15017  return(false);
15018  }
15019  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15020  VectorCount++; // not really needed but include for tidyness
15021  TotalSearchCount++;
15022  Utilities->CallLogPop(247);
15023  return(true);
15024  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15025 
15026 // check if a buffer or continuation (end of search on this leg if not found by now)
15027  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15028  {
15029  for(int x = 0; x < VectorCount; x++)
15030  {
15031  SearchVector.erase(SearchVector.end() - 1);
15032  }
15033  Utilities->CallLogPop(248);
15034  return(false);
15035  }
15036 // check if SearchVector exceeds a size of 150
15037  if(SearchVector.size() > 150)
15038  {
15039  for(int x = 0; x < VectorCount; x++)
15040  {
15041  SearchVector.erase(SearchVector.end() - 1);
15042  }
15043  Utilities->CallLogPop(1420);
15044  return(false);
15045  }
15046 // check if reached a leading point
15047  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15048  {
15049 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15050  int SearchPos1 = SearchElement.Attribute + 1;
15051  int SearchPos2;
15052  if(SearchPos1 == 2)
15053  {
15054  SearchPos1++;
15055  }
15056  if(SearchPos1 == 1)
15057  {
15058  SearchPos2 = 3;
15059  }
15060  else
15061  {
15062  SearchPos2 = 1;
15063  }
15064  SearchElement.XLink = SearchElement.Link[SearchPos1];
15065  SearchElement.XLinkPos = SearchPos1;
15066  InPrefDirFlag = false;
15067  if(SearchElement.XLink == PrefDirElement1.XLink)
15068  {
15069  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15070  InPrefDirFlag = true;
15071  }
15072  else if(SearchElement.XLink == PrefDirElement2.XLink)
15073  {
15074  SearchElement = PrefDirElement2;
15075  InPrefDirFlag = true;
15076  }
15077 // push element with XLink set to position [SearchPos1] if on a PrefDir
15078  if(InPrefDirFlag)
15079  {
15080 // check for a fouled diagonal for leading point for XLinkPos == 1)
15081  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15082  {
15083  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15084  {
15085  for(int x = 0; x < VectorCount; x++)
15086  {
15087  SearchVector.erase(SearchVector.end() - 1);
15088  }
15089  Utilities->CallLogPop(249);
15090  return(false);
15091  }
15092  }
15093  if(AutoSigsFlag)
15094  {
15095  SearchElement.AutoSignals = true;
15096  }
15097  SearchElement.PrefDirRoute = true;
15098  SearchVector.push_back(SearchElement);
15099  VectorCount++;
15100  TotalSearchCount++;
15101 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15102  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15103  AutoSigsFlag))
15104  {
15106  {
15108  {
15109  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15111  }
15112  for(int x = 0; x < VectorCount; x++)
15113  {
15114  SearchVector.erase(SearchVector.end() - 1);
15115  }
15116  Utilities->CallLogPop(1929);
15117  return(false);
15118  }
15119  Utilities->CallLogPop(250);
15120  return(true);
15121  }
15122  else
15123  {
15124 // remove leading point with XLinkPos [1]
15125  SearchVector.erase(SearchVector.end() - 1);
15126  VectorCount--;
15127  }
15128  }
15129 // XLink set to position [SearchPos2]
15130  SearchElement.XLink = SearchElement.Link[SearchPos2];
15131  SearchElement.XLinkPos = SearchPos2;
15132  if(SearchElement.XLink == PrefDirElement1.XLink)
15133  {
15134  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15135  }
15136  else if(SearchElement.XLink == PrefDirElement2.XLink)
15137  {
15138  SearchElement = PrefDirElement2;
15139  }
15140  else // failed to find a valid exit from the point
15141  {
15142  for(int x = 0; x < VectorCount; x++)
15143  {
15144  SearchVector.erase(SearchVector.end() - 1);
15145  }
15146  Utilities->CallLogPop(251);
15147  return(false);
15148  }
15149 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15150  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15151  {
15152  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15153  {
15154  for(int x = 0; x < VectorCount; x++)
15155  {
15156  SearchVector.erase(SearchVector.end() - 1);
15157  }
15158  Utilities->CallLogPop(252);
15159  return(false);
15160  }
15161  }
15162 // push element with XLink set to position [SearchPos2]
15163  if(AutoSigsFlag)
15164  {
15165  SearchElement.AutoSignals = true;
15166  }
15167  SearchElement.PrefDirRoute = true;
15168  SearchVector.push_back(SearchElement);
15169  VectorCount++;
15170  TotalSearchCount++;
15171 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15172  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15173  AutoSigsFlag))
15174  {
15176  {
15178  {
15179  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15181  }
15182  for(int x = 0; x < VectorCount; x++)
15183  {
15184  SearchVector.erase(SearchVector.end() - 1);
15185  }
15186  Utilities->CallLogPop(1930);
15187  return(false);
15188  }
15189  Utilities->CallLogPop(1592);
15190  return(true);
15191  }
15192  else
15193  {
15194  for(int x = 0; x < VectorCount; x++)
15195  {
15196  SearchVector.erase(SearchVector.end() - 1);
15197  }
15198  Utilities->CallLogPop(253);
15199  return(false);
15200  }
15201  } // if leading point
15202 
15203 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15204  SearchElement = PrefDirElement1;
15205  if(AutoSigsFlag)
15206  {
15207  SearchElement.AutoSignals = true;
15208  }
15209  SearchElement.PrefDirRoute = true;
15210  SearchVector.push_back(SearchElement);
15211  VectorCount++;
15212  TotalSearchCount++;
15213  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15214  PrefDirElement = SearchElement;
15215  } // while(true)
15216 }
15217 
15218 // ---------------------------------------------------------------------------
15219 
15220 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15221 {
15222 /*
15223  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15224  and the new or extended route created from that. Hence action varies depending on whether
15225  it is a completely new route, or an extension of an existing route at the beginning or the end.
15226  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15227  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15228 
15229  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15230  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15231  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15232  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15233  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15234  is decremented;
15235  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15236  from the existing route, then enter the new route into the AllRoutesVector;
15237  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15238  then enter the new route into the AllRoutesVector.
15239 
15240  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15241  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15242  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15243  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15244  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15245  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15246  for the new route and return;
15247  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15248  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15249 
15250  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15251  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15252  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15253 
15254 */
15255  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15256  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15257  if(SearchVector.size() < 1)
15258  {
15259  Utilities->CallLogPop(254);
15260  return;
15261  }
15263  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15264  {
15265  Utilities->CallLogPop(255);
15266  return;
15267  }
15268  TAllRoutes::TLockedRouteClass LockedRouteObject;
15269 
15271  unsigned int TruncatePrefDirPosition = 0;
15272 
15273  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15274 /* if have ReqPosRouteID:
15275  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15276  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15277  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15278  the existing route, then enter the new route into the AllRoutesVector
15279  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15280  then enter the new route into the AllRoutesVector
15281 */
15282  {
15285  {
15286  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15287  x++) // start at 1 as first element already in SearchVector
15288  {
15290  }
15291  // note that route numbers in map adjusted when ReqPos route cleared
15293  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15294  // set during ClearRouteDuringRouteBuildingAt
15296  {
15299  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15300  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15301  }
15302  }
15304  {
15306  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15307  }
15309  {
15310  SearchVector.pop_back();
15311  }
15312  }
15313  if(StartSelectionRouteID > -1)
15314 /* if have StartSelectionRouteID:
15315  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15316  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15317  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15318  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15319  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15320 */
15321  {
15323  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15324  {
15327  {
15328  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15329  for(unsigned int x = 0; x < SearchVector.size(); x++)
15330  {
15332  RouteNumber, GetFixedSearchElementAt(3, x));
15333  // find & store locked route truncate position in PrefDirVector for later use
15335  {
15336  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15337  {
15338  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15339  }
15340  }
15341  }
15343  {
15344  throw Exception("Error - failed to validate extended route for preferred route");
15345  }
15348  if(!AutoSigsFlag)
15349  {
15350  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15351  }
15352  // now add the reinstated locked route if required and set signals accordingly
15354  {
15355  LockedRouteObject.RouteNumber = RouteNumber;
15356  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15357  // now reset the signals for the locked route
15358  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15359  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15360  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15361  {
15362  // return all signals to red in route section to be truncated
15363  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15364  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15365  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15366  {
15367  TrackElement.Attribute = 0;
15368  Track->PlotSignal(10, TrackElement, Display);
15369  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15370  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15371  }
15372  }
15373  }
15374  AllRoutes->CheckMapAndRoutes(1); // test
15375  Utilities->CallLogPop(256);
15376  return;
15377  }
15379  {
15382  RouteElement.AutoSignals = true;
15383  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15384  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15385  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15386  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15387  }
15388  }
15389  else
15390  {
15392  }
15393 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15394 // AllRoutesVector hence nothing to do here
15395  }
15396  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15397  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15398  {
15399  throw Exception("Error - failed to validate single route for preferred route");
15400  }
15401  AllRoutes->StoreOneRoute(1, this);
15402  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15403  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15404  if(!AutoSigsFlag)
15405  {
15406  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15407  }
15408  AllRoutes->CheckMapAndRoutes(2); // test
15409  Utilities->CallLogPop(257);
15410 }
15411 
15412 // ---------------------------------------------------------------------------
15413 
15414 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15415 {
15416 /*
15417  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15418  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15419  & ensure signal/buffers/continuation.
15420  Note that can't select ConsecSignalsRoute for non-preferred routes.
15421  Check if train on element & disallow.
15422  Set default values for retained parameters:-
15423  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15424  StartSelectionRouteID = route that selection starts in if there is one;
15425 
15426  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15427  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15428  validity. This is just for safety reasons, the PrefDir values aren't used.
15429  StartElement1 & 2 are set to these PrefDirelements.
15430 
15431  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15432 
15433  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15434  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15435  blank StartElement2 (only want to use the route element), then return true.
15436  Check if adjacent to start or end of an existing route & disallow if so.
15437  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15438  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15439  SetRemainingSearchVectorValues().
15440  Finally add the required element to the SearchVector & return true.
15441 
15442 */
15443  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15444  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15445  ClearRoute();
15446  int TrackVectorPosition;
15447  TTrackElement TrackElement;
15448  TPrefDirElement FirstElement, LastElement;
15449 
15450  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15451  {
15452  Utilities->CallLogPop(258);
15453  return(false);
15454  }
15455  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15456  {
15457  if(!Callon)
15458  {
15459  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15460  }
15461 // makes later adjacent route checks too complicated
15462  Utilities->CallLogPop(259);
15463  return(false);
15464  }
15465  if(Track->IsLCAtHV(21, HLoc, VLoc))
15466  {
15467  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15468  Utilities->CallLogPop(1910);
15469  return(false);
15470  }
15471 // check if selected a train & disallow if so
15472  if(TrackElement.TrainIDOnElement > -1)
15473  {
15474  if(!Callon)
15475  {
15476  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15477  }
15478  Utilities->CallLogPop(260);
15479  return(false);
15480  }
15481 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15482  TPrefDirElement PrefDirElement;
15483  int LockedVectorNumber;
15484 
15485  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15486  {
15487  if(!Callon)
15488  {
15489  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15490  }
15491  Utilities->CallLogPop(261);
15492  return(false);
15493  }
15494  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15495  {
15496  if(!Callon)
15497  {
15498  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15499  }
15500  Utilities->CallLogPop(262);
15501  return(false);
15502  }
15504 // AdjacentStartRouteNumber = -1;
15505  StartRoutePosition = TrackVectorPosition;
15506 // StartRouteSelectPosition = TrackVectorPosition;
15507 
15508  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15509  TPrefDirElement PrefDirElement2(TrackElement);
15510 
15511  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15512  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15513  TPrefDirElement BlankElement;
15514 
15515  PrefDirElement1.ELinkPos = 0;
15516  PrefDirElement1.XLinkPos = 1;
15517  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15518  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15519  if(!(PrefDirElement1.EntryExitNumber()))
15520  {
15521  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15522  // no need for bridge check as bridge selections not allowed
15523  }
15524  PrefDirElement1.CheckCount = 9;
15525  PrefDirElement2.ELinkPos = 1;
15526  PrefDirElement2.XLinkPos = 0;
15527  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15528  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15529  if(!(PrefDirElement2.EntryExitNumber()))
15530  {
15531  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15532  }
15533  PrefDirElement2.CheckCount = 9; // both now set
15534 
15535 // set StartElements to the above PrefDirElements
15536  StartElement1 = PrefDirElement1;
15537  StartElement2 = PrefDirElement2;
15538 
15539 // no PrefDir check needed as doesn't need to be in a PrefDir
15540 
15541 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15543  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15544 
15545  if(RoutePair.first > -1)
15546  {
15547  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15548  {
15549  if(!Callon)
15550  {
15551  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15552  }
15553  Utilities->CallLogPop(263);
15554  return(false);
15555  }
15556  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15557  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15558  {
15559  if(!Callon)
15560  {
15561  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15562  }
15563  Utilities->CallLogPop(264);
15564  return(false);
15565  }
15566  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15567  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15568  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15569  {
15570  if(!Callon)
15571  {
15572  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15573  }
15574  Utilities->CallLogPop(265);
15575  return(false);
15576  }
15577  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15579  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15580  StartElement2 = BlankElement; // only use the route element
15582  Utilities->CallLogPop(266);
15583  return(true); // all retained values set
15584  }
15585 
15586  else // selection not in an existing route
15587  {
15588 // check if it's adjacent to start of an an existing route,
15589  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15590  {
15591  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15592  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15593  {
15594  if(!Callon)
15595  {
15596  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15597  }
15598  Utilities->CallLogPop(267);
15599  return(false);
15600  }
15601  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15602  {
15603  if(!Callon)
15604  {
15605  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15606  }
15607  Utilities->CallLogPop(268);
15608  return(false);
15609  }
15610  }
15611 // check if it's adjacent to end of an an existing route,
15612  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15613  {
15615  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15616  {
15617  if(!Callon)
15618  {
15619  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15620  }
15621  Utilities->CallLogPop(269);
15622  return(false);
15623  }
15624  }
15625  // not in a route or adjacent to start or end of a route
15626  // in this case reset all variable values to -1 & CheckCount to 4
15627  StartElement1.ELink = -1;
15628  StartElement1.ELinkPos = -1;
15629  StartElement1.XLink = -1;
15630  StartElement1.XLinkPos = -1;
15631  StartElement1.EXNumber = -1;
15633  StartElement2 = BlankElement;
15634  SearchVector.push_back(StartElement1);
15635  Utilities->CallLogPop(270);
15636  return(true);
15637  }
15638 }
15639 
15640 // ---------------------------------------------------------------------------
15641 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15642 
15643 /*
15644  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15645 
15646  Declare the following integers:-
15647  EndPosition - TrackVectorPosition for the selection;
15648  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15649  Check if selection is a valid track element and set EndPosition.
15650  Cancel if select original start element, then check that not points, bridge or crossover.
15651  Check & fail if a train is present at the selection.
15652  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15653  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15654  No check needed for selection in EveryPrefDir.
15655  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15656  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15657  as don't need it if in a route.
15658  Check if selection adj to start or end of a route and disallow.
15659  Fail if select same route as starting route, though should already have failed earlier if this is so.
15660 
15661  If there's a StartSelectionRouteID then StartElement1 will be set to
15662  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15663  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15664  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15665  to add the new route to the AllRoutesVectorPtr.
15666  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15667  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15668  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15669  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15670  the search vector values and return.
15671  If not returned yet then have failed to find the required element so return false with no message.
15672 
15673 */
15674 
15675 {
15676 // get EndPosition
15677  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15678  AnsiString(VLoc));
15679  int EndPosition;
15680 
15681  TotalSearchCount = 0;
15682  ReqPosRouteID = IDInt(-1); // for not used
15683  TTrackElement TrackElement;
15684  TPrefDirElement BlankElement;
15685 
15686  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15687  {
15688  Utilities->CallLogPop(271);
15689  return(false);
15690  }
15691 // EndPosition = EndSelectPosition;
15692 // cancel selection if on original start element
15693  if(EndPosition == StartRoutePosition)
15694  {
15695  Utilities->CallLogPop(272);
15696  return(false);
15697  }
15698  if(Track->IsLCAtHV(22, HLoc, VLoc))
15699  {
15700  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15701  Utilities->CallLogPop(1911);
15702  return(false);
15703  }
15704  if((TrackElement.TrackType == Points) && !Callon)
15705  {
15706  if(!Callon)
15707  {
15708  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15709  }
15710 // makes later adjacent route checks too complicated
15711  Utilities->CallLogPop(273);
15712  return(false);
15713  }
15714  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15715  {
15716  if(!Callon)
15717  {
15718  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15719  }
15720 // makes later adjacent route checks too complicated
15721  Utilities->CallLogPop(1861);
15722  return(false);
15723  }
15724 // check if train on element
15725  if(TrackElement.TrainIDOnElement > -1)
15726  {
15727  if(!Callon)
15728  {
15729  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15730  }
15731  Utilities->CallLogPop(274);
15732  return(false);
15733  }
15734 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15735 // check passed)
15736  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15737  TPrefDirElement EndElement2(TrackElement);
15738 
15739  EndElement1.TrackVectorPosition = EndPosition;
15740  EndElement2.TrackVectorPosition = EndPosition;
15741  EndElement1.ELinkPos = 0;
15742  EndElement1.XLinkPos = 1;
15743  EndElement1.ELink = EndElement1.Link[0];
15744  EndElement1.XLink = EndElement1.Link[1];
15745  if(!(EndElement1.EntryExitNumber()))
15746  {
15747  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15748  }
15749  EndElement1.CheckCount = 9;
15750  EndElement2.ELinkPos = 1;
15751  EndElement2.XLinkPos = 0;
15752  EndElement2.ELink = EndElement2.Link[1];
15753  EndElement2.XLink = EndElement2.Link[0];
15754  if(!(EndElement2.EntryExitNumber()))
15755  {
15756  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15757  }
15758  EndElement2.CheckCount = 9; // both now set
15759 
15760 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15761 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15762 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15763 
15764  if(EndElement1.HLoc >= StartElement1.HLoc)
15765  {
15767  SearchLimitHighH = EndElement1.HLoc + 15;
15768  }
15769  else
15770  {
15771  SearchLimitLowH = EndElement1.HLoc - 15;
15773  }
15774  if(EndElement1.VLoc >= StartElement1.VLoc)
15775  {
15777  SearchLimitHighV = EndElement1.VLoc + 15;
15778  }
15779  else
15780  {
15781  SearchLimitLowV = EndElement1.VLoc - 15;
15783  }
15784 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15785  check & TotalSearchCounts check
15786  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15787  {
15788  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15789  Utilities->CallLogPop(1694);
15790  return false;
15791  }
15792 */
15793 // don't need EveryPrefDir check for NonPreferredRoute
15794 
15795 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15796 // bool InRoute = false;
15798  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15799 
15800  if(RoutePair.first > -1)
15801  {
15802  if(RoutePair.second != 0) // not first element in existing route so no good
15803  {
15804  if(!Callon)
15805  {
15806  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15807  }
15808  Utilities->CallLogPop(275);
15809  return(false);
15810  }
15811  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15812 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15813  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15814  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15815  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15816  {
15817  if(!Callon)
15818  {
15819  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15820  }
15821  Utilities->CallLogPop(276);
15822  return(false);
15823  }
15824  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
15825  EndElement2 = BlankElement; // only need the route element
15826  EndPosition = EndElement1.TrackVectorPosition;
15827  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
15828  }
15829 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
15830  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15831  {
15832  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
15833  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
15834 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15835 // && (AdjPosition != StartRoutePosition))
15836  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15837  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15838  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
15839  {
15840  if(!Callon)
15841  {
15842  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
15843  }
15844  Utilities->CallLogPop(277);
15845  return(false);
15846  }
15847 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15848 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
15849  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15850  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15851  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
15852  (AdjPosition != StartRoutePosition))
15853  {
15854  if(!Callon)
15855  {
15856  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
15857  }
15858  Utilities->CallLogPop(278);
15859  return(false);
15860  }
15861 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
15863  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
15864  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
15865  {
15866  if(!Callon)
15867  {
15868  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
15869  }
15870  Utilities->CallLogPop(279);
15871  return(false);
15872  }
15873  }
15874 
15875 // check for same route as start element
15877  {
15878  if(!Callon)
15879  {
15880  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
15881  }
15882  Utilities->CallLogPop(280);
15883  return(false);
15884  }
15885 // check for a looping route
15886  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15887  {
15889  {
15890  if(!Callon)
15891  {
15892  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
15893  }
15894  Utilities->CallLogPop(1845);
15895  return(false);
15896  }
15897  }
15898 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15899 // so search from this element.
15900 
15901  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
15902 
15903  if(StartSelectionRouteID > -1)
15904  {
15905  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
15906  {
15908  if(PointsToBeChanged(0))
15909  {
15910  PointsChanged = true;
15911  }
15912  Utilities->CallLogPop(281);
15913  return(true);
15914  }
15915  else
15916  {
15917  if(!Callon)
15918  {
15920  }
15921  Utilities->CallLogPop(282);
15922  return(false);
15923  }
15924  }
15925  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
15926  // search on the 2 ways out of the element, which has to be a 2-ended element
15927  {
15928 // check if selection adjacent to start element and if so use that
15929  if(SearchVector.at(0).Conn[0] == EndPosition)
15930  {
15931  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
15932  {
15934  if(PointsToBeChanged(1))
15935  {
15936  PointsChanged = true;
15937  }
15938  Utilities->CallLogPop(283);
15939  return(true);
15940  }
15941  else
15942  {
15943  if(!Callon)
15944  {
15946  }
15947  Utilities->CallLogPop(284);
15948  return(false);
15949  }
15950  }
15951  else if(SearchVector.at(0).Conn[1] == EndPosition)
15952  {
15953  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
15954  {
15956  if(PointsToBeChanged(2))
15957  {
15958  PointsChanged = true;
15959  }
15960  Utilities->CallLogPop(285);
15961  return(true);
15962  }
15963  else
15964  {
15965  if(!Callon)
15966  {
15968  }
15969  Utilities->CallLogPop(286);
15970  return(false);
15971  }
15972  }
15973  // now start off in the best direction
15974  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
15975 
15976  if(SearchVector.at(0).Config[BestPos] != End)
15977  {
15978  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15979  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
15980  {
15982  if(PointsToBeChanged(3))
15983  {
15984  PointsChanged = true;
15985  }
15986  Utilities->CallLogPop(287);
15987  return(true);
15988  }
15989  }
15990  if(SearchVector.at(0).Config[1 - BestPos] != End)
15991  {
15992  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15993  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
15994  {
15996  if(PointsToBeChanged(4))
15997  {
15998  PointsChanged = true;
15999  }
16000  Utilities->CallLogPop(288);
16001  return(true);
16002  }
16003  }
16004  }
16005  if(!Callon)
16006  {
16008  }
16009  Utilities->CallLogPop(289);
16010  return(false);
16011 }
16012 
16013 // ---------------------------------------------------------------------------
16014 
16015 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16016 /*
16017  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16018  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16019  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16020  Keep a count of entries in SearchVector during the current function call, so that this number can be
16021  erased for an unproductive branch search.
16022  First check (within the loop) whether XLink leads to an End & return false if so.
16023  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16024  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16025  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16026  train on element (unless a bridge & train on different track), or if element
16027  fouls an existing diagonal route (except if element is a leading point - these checked later).
16028  Then check if found required element. If so save it & return true.
16029  If not the required element check if buffer or continuation, & if so erase all searchvector
16030  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16031  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16032  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16033  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16034  When return true have 8 items from CheckCount established, only waiting for EXNumber
16035 */
16036 {
16037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16038  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16039  int VectorCount = 0;
16040 
16041 // check for a fouled diagonal for first element. Added for v1.3.2
16042  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16043  (CurrentTrackElement.Link[XLinkPos] == 9))
16044  {
16045  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16046  {
16047  for(int x = 0; x < VectorCount; x++)
16048  {
16049  SearchVector.erase(SearchVector.end() - 1);
16050  }
16051  Utilities->CallLogPop(2044);
16052  return(false);
16053  }
16054  }
16055  while(true)
16056  {
16057  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16058  {
16059  for(int x = 0; x < VectorCount; x++)
16060  {
16061  SearchVector.erase(SearchVector.end() - 1);
16062  }
16063  Utilities->CallLogPop(1927);
16064  return(false);
16065  }
16066  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16067  {
16068  for(int x = 0; x < VectorCount; x++)
16069  {
16070  SearchVector.erase(SearchVector.end() - 1);
16071  }
16072  Utilities->CallLogPop(290);
16073  return(false);
16074  }
16075  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16076  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16077  TPrefDirElement SearchElement(NextTrackElement);
16078  SearchElement.TrackVectorPosition = NextPosition;
16079  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16080  SearchElement.ELinkPos = NextELinkPos;
16081  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16082  int NextXLinkPos;
16083  if(SearchElement.ELinkPos == 0)
16084  {
16085  NextXLinkPos = 1;
16086  }
16087  if(SearchElement.ELinkPos == 1)
16088  {
16089  NextXLinkPos = 0;
16090  }
16091  if(SearchElement.ELinkPos == 2)
16092  {
16093  NextXLinkPos = 3;
16094  }
16095  if(SearchElement.ELinkPos == 3)
16096  {
16097  NextXLinkPos = 2;
16098  }
16099  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16100  {
16101  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16102  // but may be buffers, continuation or gap
16103  SearchElement.XLinkPos = NextXLinkPos;
16104  }
16105 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16106 // can't set XLink or XLinkPos yet if the element is a leading point.
16107 
16108 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16109  for(unsigned int x = 0; x < SearchVector.size(); x++)
16110  {
16111  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16112  {
16113  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16114  // OK if it's a bridge & routes on different tracks
16115  {
16116  for(int x = 0; x < VectorCount; x++)
16117  {
16118  SearchVector.erase(SearchVector.end() - 1);
16119  }
16120  Utilities->CallLogPop(291);
16121  return(false);
16122  }
16123  }
16124  }
16125 
16126 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16127  TAllRoutes::TRouteElementPair SecondPair;
16129  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16130  if(RoutePair.first > -1)
16131  {
16132  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16133  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16134  RoutePair.second).ELinkPos)))
16135  {
16136  // still OK if start of an expected route
16137  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16138  {
16139  for(int x = 0; x < VectorCount; x++)
16140  {
16141  SearchVector.erase(SearchVector.end() - 1);
16142  }
16143  Utilities->CallLogPop(292);
16144  return(false); // only allow for start of an expected route
16145  }
16146  }
16147  }
16148  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16149  {
16150  // OK if it's a bridge & routes on different tracks
16151  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16152  SecondPair.second).ELinkPos)))
16153  {
16154  // still OK if start of an expected route
16155  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16156  {
16157  for(int x = 0; x < VectorCount; x++)
16158  {
16159  SearchVector.erase(SearchVector.end() - 1);
16160  }
16161  Utilities->CallLogPop(293);
16162  return(false); // only allow for start of an expected route
16163  }
16164  }
16165  }
16166 // check if a train on element, unless a bridge & train on different track
16167 // OK of same train as start element - no, drop this
16168 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16169  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16170  {
16171  for(int x = 0; x < VectorCount; x++)
16172  {
16173  SearchVector.erase(SearchVector.end() - 1);
16174  }
16175  Utilities->CallLogPop(294);
16176  return(false);
16177  }
16178  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16179  {
16180  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16181  {
16182  for(int x = 0; x < VectorCount; x++)
16183  {
16184  SearchVector.erase(SearchVector.end() - 1);
16185  }
16186  Utilities->CallLogPop(295);
16187  return(false);
16188  }
16189  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16190  {
16191  for(int x = 0; x < VectorCount; x++)
16192  {
16193  SearchVector.erase(SearchVector.end() - 1);
16194  }
16195  Utilities->CallLogPop(296);
16196  return(false);
16197  }
16198  }
16199 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16200  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16201  {
16202  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16203  {
16204  for(int x = 0; x < VectorCount; x++)
16205  {
16206  SearchVector.erase(SearchVector.end() - 1);
16207  }
16208  Utilities->CallLogPop(297);
16209  return(false);
16210  }
16211  }
16212 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16213 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16214 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16216  {
16217  for(int x = 0; x < VectorCount; x++)
16218  {
16219  SearchVector.erase(SearchVector.end() - 1);
16220  }
16221  Utilities->CallLogPop(1689);
16222  return(false);
16223  }
16224 // check if found it
16225  if(SearchElement.TrackVectorPosition == RequiredPosition)
16226  {
16227  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16228  {
16229  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16230  {
16231  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16232  }
16233  else
16234  {
16235  SearchElement.XLinkPos = 1;
16236  }
16237 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16238  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16239  }
16240  SearchVector.push_back(SearchElement);
16241  VectorCount++; // not really needed but include for tidyness
16242  TotalSearchCount++;
16243  Utilities->CallLogPop(298);
16244  return(true);
16245  }
16246 // Not the required element - check if a buffer or continuation
16247  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16248  {
16249  for(int x = 0; x < VectorCount; x++)
16250  {
16251  SearchVector.erase(SearchVector.end() - 1);
16252  }
16253  Utilities->CallLogPop(299);
16254  return(false);
16255  }
16256 // check if SearchVector exceeds a size of 150
16257  if(SearchVector.size() > 150)
16258  {
16259  for(int x = 0; x < VectorCount; x++)
16260  {
16261  SearchVector.erase(SearchVector.end() - 1);
16262  }
16263  Utilities->CallLogPop(1421);
16264  return(false);
16265  }
16266 // check if reached a leading point
16267  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16268  {
16269 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16270  int SearchPos1 = SearchElement.Attribute + 1;
16271  int SearchPos2;
16272  if(SearchPos1 == 2)
16273  {
16274  SearchPos1++;
16275  }
16276  if(SearchPos1 == 1)
16277  {
16278  SearchPos2 = 3;
16279  }
16280  else
16281  {
16282  SearchPos2 = 1;
16283  }
16284 // push element with XLink set to position [SearchPos1]
16285  SearchElement.XLink = SearchElement.Link[SearchPos1];
16286  SearchElement.XLinkPos = SearchPos1;
16287 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16288  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16289  {
16290  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16291  {
16292  for(int x = 0; x < VectorCount; x++)
16293  {
16294  SearchVector.erase(SearchVector.end() - 1);
16295  }
16296  Utilities->CallLogPop(300);
16297  return(false);
16298  }
16299  }
16300  SearchVector.push_back(SearchElement);
16301  VectorCount++;
16302  TotalSearchCount++;
16303 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16304 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16305 // recursive search as has to be a TTrackElement for non-preferred route searches
16306  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16307  {
16308  Utilities->CallLogPop(301);
16309  return(true);
16310  }
16311  else
16312  {
16313 // remove leading point with XLinkPos [SearchPos1]
16314  SearchVector.erase(SearchVector.end() - 1);
16315  VectorCount--;
16316 // push element with XLink set to position [SearchPos2]
16317  SearchElement.XLink = SearchElement.Link[SearchPos2];
16318  SearchElement.XLinkPos = SearchPos2;
16319 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16320  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16321  {
16322  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16323  {
16324  for(int x = 0; x < VectorCount; x++)
16325  {
16326  SearchVector.erase(SearchVector.end() - 1);
16327  }
16328  Utilities->CallLogPop(302);
16329  return(false);
16330  }
16331  }
16332  SearchVector.push_back(SearchElement);
16333  VectorCount++;
16334  TotalSearchCount++;
16335 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16336  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16337  {
16338  Utilities->CallLogPop(303);
16339  return(true);
16340  }
16341  else
16342  {
16343  for(int x = 0; x < VectorCount; x++)
16344  {
16345  SearchVector.erase(SearchVector.end() - 1);
16346  }
16347  Utilities->CallLogPop(304);
16348  return(false);
16349  }
16350  }
16351  } // if leading point
16352 
16353 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16354 // ready for next element on route
16355  SearchVector.push_back(SearchElement);
16356  VectorCount++;
16357  TotalSearchCount++;
16358  CurrentTrackElement = SearchElement;
16359  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16360  } // while(true)
16361 }
16362 
16363 // ---------------------------------------------------------------------------
16364 
16366 
16367 /*
16368  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16369  having all values set (since not necessarily on PrefDirs).
16370  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16371  (if it was the start), so these are checked first and set if necessary. All elements now have
16372  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16373  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16374  to set the route colour and direction graphics.
16375 */
16376 
16377 {
16378  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16379  if(SearchVector.size() == 0)
16380  {
16381  throw Exception("Error, SearchVector empty");
16382  }
16383 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16384 // hence need to examine and update it if necessary
16385  TPrefDirElement SecondElement;
16386 
16387  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16388  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16389  // need above check or SecondElement will fail
16390  {
16391  SecondElement = SearchVector.at(1);
16392  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16393  for(int x = 0; x < 4; x++)
16394  {
16395  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16396  {
16397  if(SearchVector.at(0).XLink == -1) // i.e. not set
16398  {
16399  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16400  SearchVector.at(0).XLinkPos = x;
16401  }
16402  int ELinkPos;
16403  if(SearchVector.at(0).XLinkPos == 0)
16404  {
16405  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16406  }
16407  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16408  if(SearchVector.at(0).XLinkPos == 1)
16409  {
16410  ELinkPos = 0;
16411  }
16412  if(SearchVector.at(0).XLinkPos == 2)
16413  {
16414  ELinkPos = 3;
16415  }
16416  if(SearchVector.at(0).XLinkPos == 3)
16417  {
16418  ELinkPos = 2;
16419  }
16420  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16421  {
16422  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16423  SearchVector.at(0).ELinkPos = ELinkPos;
16424  }
16425  break; // no point going any further
16426  }
16427  }
16428  }
16429  for(unsigned int x = 0; x < SearchVector.size(); x++)
16430  {
16431  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16432 // set EXNumber
16433  if(!(SearchVector.at(x).EntryExitNumber()))
16434  {
16435  throw Exception("Error in EntryExitNumber 3");
16436  }
16437  SearchVector.at(x).CheckCount++;
16438 // all values now incorporated
16439  }
16440 
16441  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16442 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16443 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16444  Utilities->CallLogPop(305);
16445 }
16446 
16447 // ---------------------------------------------------------------------------
16448 
16450 
16451 /*
16452  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16453  AutoSigsRoute.
16454  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16455  beginning or the end.
16456  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16457  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16458  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16459  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16460  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16461  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16462  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16463 
16464  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16465  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16466  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16467  route at the start.
16468 
16469  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16470  for the new route and return.
16471 */
16472 
16473 {
16474  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16475  AnsiString(ReqPosRouteID.GetInt()));
16476  if(SearchVector.size() < 1)
16477  {
16478  Utilities->CallLogPop(306);
16479  return;
16480  }
16481  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16482  if(!ValidatePrefDir(6))
16483  {
16484  Utilities->CallLogPop(307);
16485  return;
16486  }
16487  TAllRoutes::TLockedRouteClass LockedRouteObject;
16488 
16490  unsigned int TruncatePrefDirPosition = 0;
16491 
16492  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16493 /* if have ReqPosRouteID:
16494  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16495  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16496  then enter the new route into the AllRoutesVector
16497 */
16498  {
16500  {
16501  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16502  x++) // start at 1 as first element already in SearchVector
16503  {
16505  }
16506  // note that route numbers in map adjusted when ReqPos route cleared
16508  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16509  // set during ClearRouteDuringRouteBuildingAt)
16511  {
16514  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16515  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16516  }
16517  }
16519  {
16520  SearchVector.pop_back();
16521  }
16522  }
16523  if(StartSelectionRouteID > -1)
16524 /* if have StartSelectionRouteID:
16525  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16526  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16527 */
16528  {
16530  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16531  {
16533  {
16534  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16535  for(unsigned int x = 0; x < SearchVector.size(); x++)
16536  {
16538  RouteNumber, GetFixedSearchElementAt(7, x));
16539  // find & store locked route truncate position in PrefDirVector for later use
16541  {
16542  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16543  {
16544  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16545  }
16546  }
16547  }
16549  {
16550  throw Exception("Failed to validate extended route for nonpreferred route");
16551  }
16554  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16555  // now add the reinstated locked route if required and set signals accordingly
16556  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16557  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16558  // that I haven't thought of
16560  {
16561  LockedRouteObject.RouteNumber = RouteNumber;
16562  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16563  // now reset the signals for the locked route
16564  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16565  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16566  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16567  {
16568  // return all signals to red in route section to be truncated
16569  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16570  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16571  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16572  {
16573  TrackElement.Attribute = 0;
16574  Track->PlotSignal(11, TrackElement, Display);
16575  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16576  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16577  }
16578  }
16579  }
16580  AllRoutes->CheckMapAndRoutes(3); // test
16581  Utilities->CallLogPop(308);
16582  return;
16583  }
16584  }
16585  else
16586  {
16588  }
16589 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16590 // hence nothing to do here
16591  }
16592  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16593  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16594  {
16595  throw Exception("Failed to validate single route for nonpreferred route");
16596  }
16597  AllRoutes->StoreOneRoute(2, this);
16598  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16599  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16600  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16601  AllRoutes->CheckMapAndRoutes(4); // test
16602  Utilities->CallLogPop(309);
16603 }
16604 
16605 // ---------------------------------------------------------------------------
16606 
16607 void TOneRoute::SetRoutePoints(int Caller) const
16608 /*
16609  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16610  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16611  when they were created.
16612 */
16613 {
16614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16615  if(!PrefDirVector.empty())
16616  {
16617  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16618  {
16619  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16620  {
16621  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16622  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16623  }
16624  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16625  {
16626  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16627  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16628  }
16629  }
16630  }
16631  Utilities->CallLogPop(327);
16632 }
16633 
16634 // ---------------------------------------------------------------------------
16635 
16636 void TOneRoute::SetRouteSignals(int Caller) const
16637 /* Used for new train additions in AddTrain and in route setting
16638  Set the signals as follows:-
16639  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16640  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16641  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16642  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16643  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16644  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16645  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16646  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16647  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16648 
16649  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16650  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16651  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16652  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16653  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16654  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16655  as a green signal.
16656 */
16657 {
16658  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16659  if(!PrefDirVector.empty())
16660  {
16661  // get target Attribute value, check first if there is a forward linked route
16662  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16663  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16664  int ForwardLinkedRouteNumber, Attribute = 0;
16665  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16666  // Note that LastElement can't be points but can be linked to points
16667  {
16668  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16669  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16670  {
16671  if(ForwardLinkedRouteNumber > -1)
16672  {
16673  int NextForwardLinkedRouteNumber = -1;
16674  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16675  Attribute)))
16676  {
16677  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16678  }
16679  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16680  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16681  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16682  }
16683  }
16684  }
16685  int RouteNumber;
16686  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16687  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16688  if(RouteType != TAllRoutes::NoRoute)
16689  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16690  {
16691  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16692  }
16693  }
16694  Utilities->CallLogPop(1720);
16695 }
16696 
16697 // ---------------------------------------------------------------------------
16698 
16699 bool TOneRoute::PointsToBeChanged(int Caller) const
16700 {
16701  // true if at any point in SearchVector points have to be changed
16702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16703  if(!SearchVector.empty())
16704  {
16705  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16706  {
16707  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16708  {
16709  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16710  {
16711  Utilities->CallLogPop(1717);
16712  return(true);
16713  }
16714  }
16715  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16716  {
16717  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16718  {
16719  Utilities->CallLogPop(1718);
16720  return(true);
16721  }
16722  }
16723  }
16724  }
16725  Utilities->CallLogPop(1719);
16726  return(false);
16727 }
16728 
16729 // ---------------------------------------------------------------------------
16730 
16731 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16732 /*
16733  Works forward through the route until finds:-
16734  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16735  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16736  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16737  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16738  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16739  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16740  returns true;
16741  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16742 */
16743 {
16744  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16745  Attribute = 0;
16746  NextForwardLinkedRouteNumber = -1;
16747  for(unsigned int x = 0; x < PrefDirSize(); x++)
16748  {
16749  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16750  if(PrefDirVector.at(x).TrackType == Bridge)
16751  {
16752  if(PrefDirVector.at(x).XLinkPos < 2)
16753  {
16754  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16755  }
16756  else
16757  {
16758  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16759  }
16760  }
16761  if(TrainID != -1)
16762  {
16763  Utilities->CallLogPop(328);
16764  return(true);
16765  }
16766  if(PrefDirVector.at(x).TrackType == Buffers)
16767  {
16768  Attribute = 1;
16769  Utilities->CallLogPop(329);
16770  return(true);
16771  }
16772  if(PrefDirVector.at(x).TrackType == Continuation)
16773  {
16774  Attribute = 3;
16775  Utilities->CallLogPop(330);
16776  return(true);
16777  }
16778  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16779  {
16780  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16781  {
16782  Attribute = 0;
16783  Utilities->CallLogPop(1950);
16784  return(true);
16785  }
16786  }
16787  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16788  {
16789  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16790  if(Attribute > 3)
16791  {
16792  Attribute = 3;
16793  }
16794  Utilities->CallLogPop(331);
16795  return(true);
16796  }
16797  if(x == PrefDirSize() - 1)
16798  {
16799  TPrefDirElement LastElement = PrefDirVector.at(x);
16800  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16801  {
16802  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16803  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16804  {
16805  Attribute = 0;
16806  Utilities->CallLogPop(332);
16807  return(false);
16808  }
16809  }
16810  }
16811  }
16812  Utilities->CallLogPop(333);
16813  return(true);
16814 }
16815 
16816 // ---------------------------------------------------------------------------
16817 
16818 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16819 /*
16820  This function is only called by TAllRoutes::SetAllRearwardsSignals.
16821 
16822  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16823  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16824  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16825  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16826  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16827  a route.
16828 
16829  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16830  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16831  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
16832  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
16833 
16834  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
16835  and the next rearwards signal becomes yellow, although it's the first in the route
16836 */
16837 {
16838  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
16839  AnsiString(PrefDirVectorStartPosition));
16840  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
16841  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
16842 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
16843 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
16844  bool SkipContinuationAndBufferAttributeChange = false;
16845 
16846  if(!PrefDirVector.empty())
16847  {
16848  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
16849  {
16850  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16851  if(PrefDirPtr->TrackType == Bridge)
16852  {
16853  if(PrefDirPtr->XLinkPos < 2)
16854  {
16855  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16856  }
16857  else
16858  {
16859  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16860  }
16861  }
16862  if(TrainID != -1)
16863  {
16864  SkipContinuationAndBufferAttributeChange = true;
16865  break;
16866  }
16867  }
16868 
16871  {
16872  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
16873  AutoSigVectorIT++)
16874  {
16875  if(!AllRoutes->AllRoutesVector.empty())
16876  {
16877  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
16878  {
16879  SkipContinuationAndBufferAttributeChange = true;
16880  break;
16881  }
16882  }
16883  }
16884  }
16886  {
16887  SkipContinuationAndBufferAttributeChange = true;
16888  }
16889  if(!SkipContinuationAndBufferAttributeChange)
16890  {
16891  if(PrefDirVector.back().TrackType == Buffers)
16892  {
16893  Attribute = 1; // treat buffer as red signal
16894  }
16895  if(PrefDirVector.back().TrackType == Continuation)
16896  {
16897  Attribute = 3; // treat continuation as a green signal
16898  }
16899  }
16900  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16901  {
16902  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16903  if(PrefDirPtr->TrackType == Bridge)
16904  {
16905  if(PrefDirPtr->XLinkPos < 2)
16906  {
16907  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16908  }
16909  else
16910  {
16911  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16912  }
16913  }
16914  if(TrainID != -1)
16915  {
16916  Utilities->CallLogPop(334);
16917  return(false);
16918  }
16919  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
16920  // the attribute to 0 so first signal behind the LC is red
16921  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16922  {
16923  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16924  {
16925  Attribute = 0;
16926  }
16927  }
16928 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
16929 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
16930  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
16931  {
16932  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
16933  PrefDirPtr->PrefDirRoute)
16934  {
16935  if(Attribute < 3)
16936  {
16937  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
16938  }
16939  else
16940  {
16941  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
16942  }
16943  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
16944  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
16945  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
16946  {
16947  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16948  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
16949  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16950  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
16951  }
16952  if(Attribute < 3)
16953  {
16954  Attribute++;
16955  }
16956  Display->Update(); // update after recent plots
16957  }
16958  }
16959  }
16960  }
16961  Utilities->CallLogPop(335);
16962  return(true);
16963 }
16964 
16965 // ---------------------------------------------------------------------------
16966 
16967 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
16968 /*
16969  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
16970  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
16971  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
16972  Selection invalid if select a bridge; trying to leave a single element; last element to be left
16973  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
16974  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
16975  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
16976  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
16977 */
16978 {
16979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16980  "," + AnsiString((short)PrefDirRoute));
16981  bool ElementInRoute = false;
16982  bool TrainOccupyingRoute = false;
16983 
16984  for(unsigned int b = 0; b < PrefDirSize(); b++)
16985  {
16986  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
16987  {
16988  ElementInRoute = true;
16989  break;
16990  }
16991  }
16992  if(!ElementInRoute)
16993  {
16994  ReturnFlag = NotInRoute;
16995  Utilities->CallLogPop(336);
16996  return;
16997  }
16998 // it is in the route so continue, first look for a train or a flashing level crossing
16999  for(int b = PrefDirSize() - 1; b >= 0; b--)
17000  {
17001  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17002  if(PrefDirVector.at(b).TrackType == Bridge)
17003  {
17004  if(PrefDirVector.at(b).XLinkPos < 2)
17005  {
17006  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17007  }
17008  else
17009  {
17010  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17011  }
17012  }
17013  if(TrainID != -1)
17014  {
17015 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17016 // ReturnFlag = InRouteFalse;
17017 // Utilities->CallLogPop(337);
17018 // return;
17019 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17020  TrainOccupyingRoute = true; // train is forward of the truncate point
17021  }
17022  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17023  {
17024  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17025  ReturnFlag = InRouteFalse;
17026  Utilities->CallLogPop(1941);
17027  return;
17028  }
17029  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17030  {
17031  break; // OK found truncate element & no flashing LC in front
17032  }
17033  }
17034 
17035  for(unsigned int b = 0; b < PrefDirSize(); b++)
17036  {
17037  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17038  {
17039  if(PrefDirVector.at(b).TrackType == Bridge)
17040  {
17041  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17042  ReturnFlag = InRouteFalse;
17043  Utilities->CallLogPop(338);
17044  return;
17045  }
17046  if(b == 1)
17047  {
17048  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17049  ReturnFlag = InRouteFalse;
17050  Utilities->CallLogPop(339);
17051  return;
17052  }
17053  if(b > 0)
17054  {
17055  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17056  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17057  {
17058  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17059  {
17060  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17061  ReturnFlag = InRouteFalse;
17062  Utilities->CallLogPop(340);
17063  return;
17064  }
17065  }
17066  else
17067  {
17068  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17069  {
17070  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17071  ReturnFlag = InRouteFalse;
17072  Utilities->CallLogPop(341);
17073  return;
17074  }
17075  }
17076  }
17077  int RouteNumber;
17079 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17080 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17081 
17082 // check if part of this route already locked & disallow if so
17083  if(!(AllRoutes->LockedRouteVector.empty()))
17084  {
17086  {
17087  if(LRVIT->RouteNumber == RouteNumber)
17088  {
17089  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17090  ReturnFlag = InRouteFalse;
17091  Utilities->CallLogPop(749);
17092  return;
17093  }
17094  }
17095  }
17096  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17097  // RouteLockingRequired only checks for trains approaching
17098  {
17101  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17102  L"Warning!", MB_YESNO | MB_ICONWARNING);
17103  TrainController->BaseTime = TDateTime::CurrentDateTime();
17105  if(button == IDNO)
17106  {
17107  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17108  Utilities->CallLogPop(342);
17109  return;
17110  }
17111  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17112  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17113  TAllRoutes::TLockedRouteClass LockedRoute;
17114  bool ExistingLockedRouteModified = false;
17115  LockedRoute.RouteNumber = RouteNumber;
17116  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17117  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17118  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17119  LockedRoute.LockStartTime = TrainController->TTClockTime;
17120 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17121 // to use the new TruncateTrackVectorPosition & LockStartTime
17122  if(!AllRoutes->LockedRouteVector.empty())
17123  {
17124  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17125  LRVIT++)
17126  {
17127  if(LRVIT->RouteNumber == RouteNumber)
17128  {
17129  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17130  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17131  ExistingLockedRouteModified = true;
17132  }
17133  }
17134  }
17135  if(!ExistingLockedRouteModified)
17136  {
17137  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17138  }
17139  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17140  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17141  {
17142  // return all signals to red in route section to be truncated
17143  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17144  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17145  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17146  {
17147  TrackElement.Attribute = 0;
17148  Track->PlotSignal(2, TrackElement, Display);
17149  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17150  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17151  }
17152  }
17153 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17154  ReturnFlag = InRouteTrue;
17155  }
17156  else
17157  {
17158  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17159  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17160  {
17161  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17162  ReturnFlag = InRouteTrue;
17163  }
17164  }
17165  AllRoutes->CheckMapAndRoutes(5); // test
17166  Utilities->CallLogPop(343);
17167  return;
17168  }
17169  }
17170  ReturnFlag = NotInRoute;
17171  Utilities->CallLogPop(344);
17172 }
17173 
17174 // ---------------------------------------------------------------------------
17176 /*
17177  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17178  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17179  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17180  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17181  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17182  the route colours.
17183 */
17184 {
17185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17186  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17188  int RouteNumber;
17189  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17190  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17191 
17192  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17193  {
17194  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17195  {
17196  if(PrefDirVector.at(x).TrackType == SignalPost)
17197  {
17198  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17199  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17200  }
17201  }
17202  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17203 // already set all signals to red in route so start at start of route for further rearwards signal setting
17204  }
17205  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17206  {
17207  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17208  }
17209  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17210  AllRoutes->CheckMapAndRoutes(9); // test
17211  TrainController->BaseTime = TDateTime::CurrentDateTime();
17213  Utilities->CallLogPop(345);
17214  return;
17215 }
17216 
17217 // ---------------------------------------------------------------------------
17218 
17219 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17220 /*
17221  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17222 */
17223 {
17224  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17225  AnsiString((short)PrefDirRoute));
17226  if(SearchVector.empty())
17227  {
17228  Utilities->CallLogPop(1149);
17229  return;
17230  }
17231  for(unsigned int b = 0; b < SearchVector.size(); b++)
17232  {
17235  PrefDirRoute);
17236  }
17237  Utilities->CallLogPop(346);
17238 }
17239 
17240 // ---------------------------------------------------------------------------
17241 
17242 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17243 /*
17244  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17245  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17246  TOneRoute.
17247 */
17248 {
17249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17250  AnsiString((short)PrefDirRoute));
17251  RouteFlash.RouteFlashVector.clear();
17252  TRouteFlashElement RouteFlashElement;
17253 
17254  for(unsigned int b = 0; b < SearchVector.size(); b++)
17255  {
17256  int H = GetFixedSearchElementAt(11, b).HLoc;
17257  int V = GetFixedSearchElementAt(12, b).VLoc;
17259  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17260  RouteFlashElement.HLoc = H;
17261  RouteFlashElement.VLoc = V;
17263  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17264  }
17265  Utilities->CallLogPop(348);
17266 }
17267 
17268 // ---------------------------------------------------------------------------
17269 
17270 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17271 {
17272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17273  if(!PrefDirVector.empty())
17274  {
17275  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17276  {
17277  int H = PrefDirPtr->HLoc;
17278  int V = PrefDirPtr->VLoc;
17279  // check for any LCs that are closed to trains & set the flash values and store in the vector
17280  if(Track->IsLCAtHV(39, H, V))
17281  {
17282  if(Track->IsLCBarrierUpAtHV(0, H, V))
17283  {
17284  Track->LCChangeFlag = true;
17285  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17286  CLC.HLoc = H;
17287  CLC.VLoc = V;
17289  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17292  if(PrefDirRoute)
17293  {
17294  CLC.TypeOfRoute = 1;
17295  }
17296  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17297  Track->ChangingLCVector.push_back(CLC);
17298  }
17299  }
17300  }
17301  }
17302  Utilities->CallLogPop(1948);
17303 }
17304 
17305 // ---------------------------------------------------------------------------
17306 
17308 /*
17309  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17310  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17311  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17312  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17313 */
17314 {
17315  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17316  if(!OverlayPlotted)
17317  {
17318  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17319  {
17320  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17321  {
17322  continue;
17323  }
17324  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17325  Display->Update();
17326  }
17327  OverlayPlotted = true;
17328  }
17329  Utilities->CallLogPop(349);
17330 }
17331 
17332 // ---------------------------------------------------------------------------
17333 
17335 /*
17336  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17337  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17338  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17339  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17340 */
17341 {
17342  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17343  if(OverlayPlotted)
17344  {
17345  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17346  {
17347  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17348  {
17349  continue;
17350  }
17351  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17352  Display->Update();
17353  }
17354  OverlayPlotted = false;
17355  }
17356  Utilities->CallLogPop(350);
17357 }
17358 
17359 // ---------------------------------------------------------------------------
17360 
17361 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17362 {
17363  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17364  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17365  {
17366  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17367  }
17368  Utilities->CallLogPop(120);
17369  return(AllRoutesVector.at(At));
17370 }
17371 
17372 // ---------------------------------------------------------------------------
17373 // ---------------------------------------------------------------------------
17374 
17376 {
17377  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17378  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17379  {
17380  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17381  }
17382  Utilities->CallLogPop(121);
17383  return(AllRoutesVector.at(At));
17384 }
17385 
17386 // ---------------------------------------------------------------------------
17387 
17388 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17389 /*
17390  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17391 */
17392 {
17393  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17394  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17395  {
17396  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17397  }
17398  Utilities->CallLogPop(351);
17399 }
17400 
17401 // ---------------------------------------------------------------------------
17402 
17403 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17404 {
17405  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17406  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17407  {
17408  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17409  }
17410  Utilities->CallLogPop(1706);
17411 }
17412 
17413 // ---------------------------------------------------------------------------
17414 
17415 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17416 /*
17417  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17418  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17419  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17420  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17421  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17422  length (train length).
17423 */
17424 {
17425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17426  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17427  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17428  {
17429  TTruncateReturnType ReturnFlag;
17430  RouteTruncateFlag = true;
17431 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17432  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17433  RouteTruncateFlag = false;
17434  if(ReturnFlag == NotInRoute)
17435  {
17436  continue;
17437  }
17438  else if(ReturnFlag == InRouteTrue)
17439  {
17440  Utilities->CallLogPop(352);
17441  return(true);
17442  }
17443  else if(ReturnFlag == InRouteFalse)
17444  {
17445  Utilities->CallLogPop(353);
17446  return(false);
17447  }
17448  }
17449  Utilities->CallLogPop(354);
17450  return(false);
17451 }
17452 
17453 // ---------------------------------------------------------------------------
17454 
17455 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17456 /*
17457  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17458  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17459 */
17460 {
17461  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17462  AnsiString(LinkPos));
17463  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17464  {
17465  Utilities->CallLogPop(355);
17466  return(false);
17467  }
17468  THVPair Route2MultiMapKeyPair;
17469 
17470  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17471  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17472  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17473  TRoute2MultiMapIterator Route2MultiMapIterator;
17474 
17475  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17476  {
17477  Utilities->CallLogPop(356);
17478  return(false);
17479  }
17480  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17481  {
17482  Utilities->CallLogPop(1422);
17483  return(true);
17484  }
17485  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17486  {
17487  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17488 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17489 // realised after writing this that can't be points as would have been covered above, but leave anyway
17490  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17491  Route2MultiMapIterator->second.second);
17492  EntryLinkPos = PrefDirElement1.ELinkPos;
17493  ExitLinkPos = PrefDirElement1.XLinkPos;
17494  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17495  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17496  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17497  {
17498  Utilities->CallLogPop(357);
17499  return(true);
17500  }
17501  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17502  {
17503  Utilities->CallLogPop(358);
17504  return(true);
17505  }
17506  }
17507  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17508  {
17509  Utilities->CallLogPop(1423);
17510  return(true);
17511  }
17512  Utilities->CallLogPop(363);
17513  return(false); // none found
17514 }
17515 
17516 // ---------------------------------------------------------------------------
17517 
17518 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17519  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17520 /*
17521  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17522  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17523  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17524  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17525  for replotting of AutoSigsRoutes.
17526 */
17527 {
17528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17529  AnsiString(LinkPos));
17530  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17531  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17532  if(TrackVectorPosition == -1)
17533  {
17534  Utilities->CallLogPop(364);
17535  return(NoRoute); // allows for continuation entries & exits
17536  }
17537  THVPair Route2MultiMapKeyPair;
17538 
17539  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17540  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17541  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17542  TRoute2MultiMapIterator Route2MultiMapIterator;
17543 
17544  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17545  {
17546  Utilities->CallLogPop(365);
17547  return(NoRoute); // none found
17548  }
17549  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17550  {
17551  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17552 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17553  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17554  Route2MultiMapIterator->second.second);
17555  EntryLinkPos = PrefDirElement1.ELinkPos;
17556  ExitLinkPos = PrefDirElement1.XLinkPos;
17557  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17558  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17559  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17560  {
17561  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17562  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17563  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17564  {
17565  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17566  }
17567  if(PrefDirElement1.AutoSignals)
17568  {
17569  Utilities->CallLogPop(366);
17570  return(AutoSigsRoute);
17571  }
17572  else
17573  {
17574  Utilities->CallLogPop(367);
17575  return(NotAutoSigsRoute);
17576  }
17577  }
17578  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17579  {
17580  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17581  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17582  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17583  {
17584  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17585  }
17586  if(PrefDirElement1.AutoSignals)
17587  {
17588  Utilities->CallLogPop(368);
17589  return(AutoSigsRoute);
17590  }
17591  else
17592  {
17593  Utilities->CallLogPop(369);
17594  return(NotAutoSigsRoute);
17595  }
17596  }
17597  }
17598  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17599  {
17600  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17601  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17602 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17603  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17604  EntryLinkPos = PrefDirElement2.ELinkPos;
17605  ExitLinkPos = PrefDirElement2.XLinkPos;
17606  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17607  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17608  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17609  {
17610  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17611  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17612  {
17613  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17614  }
17615  if(PrefDirElement2.AutoSignals)
17616  {
17617  Utilities->CallLogPop(370);
17618  return(AutoSigsRoute);
17619  }
17620  else
17621  {
17622  Utilities->CallLogPop(371);
17623  return(NotAutoSigsRoute);
17624  }
17625  }
17626  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17627  {
17628  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17629  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17630  {
17631  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17632  }
17633  if(PrefDirElement2.AutoSignals)
17634  {
17635  Utilities->CallLogPop(372);
17636  return(AutoSigsRoute);
17637  }
17638  else
17639  {
17640  Utilities->CallLogPop(373);
17641  return(NotAutoSigsRoute);
17642  }
17643  }
17644  ItPair.second--; // the second iterator points one past the last matching value
17645  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17646  EntryLinkPos = PrefDirElement3.ELinkPos;
17647  ExitLinkPos = PrefDirElement3.XLinkPos;
17648  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17649  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17650  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17651  {
17652  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17653  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17654  {
17655  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17656  }
17657  if(PrefDirElement3.AutoSignals)
17658  {
17659  Utilities->CallLogPop(374);
17660  return(AutoSigsRoute);
17661  }
17662  else
17663  {
17664  Utilities->CallLogPop(375);
17665  return(NotAutoSigsRoute);
17666  }
17667  }
17668  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17669  {
17670  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17671  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17672  {
17673  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17674  }
17675  if(PrefDirElement3.AutoSignals)
17676  {
17677  Utilities->CallLogPop(376);
17678  return(AutoSigsRoute);
17679  }
17680  else
17681  {
17682  Utilities->CallLogPop(377);
17683  return(NotAutoSigsRoute);
17684  }
17685  }
17686  }
17687  Utilities->CallLogPop(378);
17688  return(NoRoute); // none found
17689 }
17690 
17691 // ---------------------------------------------------------------------------
17692 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17693 /*
17694  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17695  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17696 */
17697 {
17698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17699  AnsiString(LinkPos));
17700  if(TrackVectorPosition == -1)
17701  {
17702  RouteNumber = -1;
17703  Utilities->CallLogPop(379);
17704  return(NoRoute); // allows for continuation & buffer entries & exits
17705  }
17706  THVPair Route2MultiMapKeyPair;
17707 
17708  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17709  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17710  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17711  TRoute2MultiMapIterator Route2MultiMapIterator;
17712 
17713  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17714  {
17715  RouteNumber = -1;
17716  Utilities->CallLogPop(380);
17717  return(NoRoute); // none found
17718  }
17719  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17720  {
17721  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17722 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17723  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17724  Route2MultiMapIterator->second.second);
17725  EntryLinkPos = PrefDirElement1.ELinkPos;
17726  ExitLinkPos = PrefDirElement1.XLinkPos;
17727  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17728  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17729  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17730  {
17731  RouteNumber = Route2MultiMapIterator->second.first;
17732  if(PrefDirElement1.AutoSignals)
17733  {
17734  Utilities->CallLogPop(381);
17735  return(AutoSigsRoute);
17736  }
17737  else
17738  {
17739  Utilities->CallLogPop(382);
17740  return(NotAutoSigsRoute);
17741  }
17742  }
17743  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17744  {
17745  RouteNumber = Route2MultiMapIterator->second.first;
17746  if(PrefDirElement1.AutoSignals)
17747  {
17748  Utilities->CallLogPop(383);
17749  return(AutoSigsRoute);
17750  }
17751  else
17752  {
17753  Utilities->CallLogPop(384);
17754  return(NotAutoSigsRoute);
17755  }
17756  }
17757  }
17758  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17759  {
17760  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17761  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17762 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17763  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17764  EntryLinkPos = PrefDirElement2.ELinkPos;
17765  ExitLinkPos = PrefDirElement2.XLinkPos;
17766  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17767  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17768  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17769  {
17770  RouteNumber = ItPair.first->second.first;
17771  if(PrefDirElement2.AutoSignals)
17772  {
17773  Utilities->CallLogPop(385);
17774  return(AutoSigsRoute);
17775  }
17776  else
17777  {
17778  Utilities->CallLogPop(386);
17779  return(NotAutoSigsRoute);
17780  }
17781  }
17782  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17783  {
17784  RouteNumber = ItPair.first->second.first;
17785  if(PrefDirElement2.AutoSignals)
17786  {
17787  Utilities->CallLogPop(387);
17788  return(AutoSigsRoute);
17789  }
17790  else
17791  {
17792  Utilities->CallLogPop(388);
17793  return(NotAutoSigsRoute);
17794  }
17795  }
17796  ItPair.second--; // the second iterator points one past the last matching value
17797  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17798  EntryLinkPos = PrefDirElement3.ELinkPos;
17799  ExitLinkPos = PrefDirElement3.XLinkPos;
17800  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17801  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17802  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17803  {
17804  RouteNumber = ItPair.second->second.first;
17805  if(PrefDirElement3.AutoSignals)
17806  {
17807  Utilities->CallLogPop(389);
17808  return(AutoSigsRoute);
17809  }
17810  else
17811  {
17812  Utilities->CallLogPop(390);
17813  return(NotAutoSigsRoute);
17814  }
17815  }
17816  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
17817  {
17818  RouteNumber = ItPair.second->second.first;
17819  if(PrefDirElement3.AutoSignals)
17820  {
17821  Utilities->CallLogPop(391);
17822  return(AutoSigsRoute);
17823  }
17824  else
17825  {
17826  Utilities->CallLogPop(392);
17827  return(NotAutoSigsRoute);
17828  }
17829  }
17830  }
17831  RouteNumber = -1;
17832  Utilities->CallLogPop(393);
17833  return(NoRoute); // none found
17834 }
17835 
17836 // ---------------------------------------------------------------------------
17837 
17838 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
17839 /*
17840  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
17841  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
17842  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
17843  and Route2MultiMap.
17844 */
17845 {
17846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
17847  TOneRoute EmptyRoute;
17848 
17849  EmptyRoute.RouteID = NextRouteID;
17850  NextRouteID++;
17851 
17852  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17853  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17854  {
17855  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
17856  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
17857  }
17858  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
17859  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
17860 
17861  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
17862  Utilities->CallLogPop(394);
17863 }
17864 
17865 // ---------------------------------------------------------------------------
17866 
17868 /*
17869  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
17870  that is already in Route is used.
17871 */
17872 {
17873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
17874  TOneRoute EmptyRoute;
17875 
17876  EmptyRoute.RouteID = Route->RouteID;
17877 
17878  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17879  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17880  {
17881  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
17882  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
17883  }
17884  Utilities->CallLogPop(1579);
17885 }
17886 
17887 // ---------------------------------------------------------------------------
17888 
17889 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
17890 /*
17891  When attaching a new route section to an existing route, it is sometimes necessary to erase the
17892  original route and create a new composite route. This function Erases all elements in the route
17893  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
17894  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
17895  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
17896  that are greater than the route number that is removed. The LockedRouteVector as also searched
17897  and if any relate to the route that has been cleared they are erased too, but the fact that one
17898  has been found is recorded so that it can be re-established later.
17899 */
17900 {
17901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
17902  THVPair Route2MultiMapKeyPair;
17903  TRoute2MultiMapEntry Route2MultiMapEntry;
17904  TRoute2MultiMapIterator Route2MultiMapIterator;
17905 
17906 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
17907 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
17908 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
17909 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
17910 // If so the locked route is removed from the locked vector and is lost.
17911  LockedRouteTruncateTrackVectorPosition = 0;
17912  LockedRouteLastTrackVectorPosition = 0;
17913  LockedRouteLastXLinkPos = 0;
17914  LockedRouteLockStartTime = TDateTime(0);
17915  if(!LockedRouteVector.empty())
17916  {
17917  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17918  {
17919  if(LRVIT->RouteNumber == RouteNumber)
17920  {
17921  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
17922  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
17923  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
17924  LockedRouteLockStartTime = LRVIT->LockStartTime;
17925  LockedRouteFoundDuringRouteBuilding = true;
17926  LockedRouteVector.erase(LRVIT);
17927  }
17928  }
17929  }
17930  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
17931  {
17932  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
17933  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
17934  }
17935  Utilities->CallLogPop(395);
17936 }
17937 
17938 // ---------------------------------------------------------------------------
17939 
17941  TRoute2MultiMapIterator &Route2MultiMapIterator)
17942 /*
17943  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
17944  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
17945  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
17946  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
17947  are given for failure.
17948 */
17949 {
17950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
17951  AnsiString(VLoc) + "," + AnsiString(ELink));
17952  TRouteElementPair ReturnPair;
17953 
17954  ReturnPair.first = -1;
17955  ReturnPair.second = 0;
17956  THVPair Route2MultiMapKeyPair;
17957 
17958  Route2MultiMapKeyPair.first = HLoc;
17959  Route2MultiMapKeyPair.second = VLoc;
17960  TRoute2MultiMapEntry Route2MultiMapEntry;
17961 
17962  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
17963  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17964 
17965  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17966  Route2MultiMapIterator = ItPair.first;
17967 
17968  if(ItPair.first == ItPair.second)
17969  {
17970  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
17971  }
17972  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
17973  {
17974  ReturnPair.first = ItPair.first->second.first;
17975  ReturnPair.second = ItPair.first->second.second;
17976  Route2MultiMapIterator = ItPair.first;
17977  Utilities->CallLogPop(396);
17978  return(ReturnPair);
17979  }
17980  ItPair.first++;
17981  if(ItPair.first == ItPair.second)
17982  {
17983  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
17984  }
17985  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
17986  {
17987  ReturnPair.first = ItPair.first->second.first;
17988  ReturnPair.second = ItPair.first->second.second;
17989  Route2MultiMapIterator = ItPair.first;
17990  Utilities->CallLogPop(397);
17991  return(ReturnPair);
17992  }
17993  Utilities->CallLogPop(398);
17994  return(ReturnPair);
17995 }
17996 
17997 // ---------------------------------------------------------------------------
17998 
17999 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18000 /*
18001  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18002  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
18003  RouteNumber (route position in AllRoutes vector is returned as a reference.
18004  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18005  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18006 */
18007 {
18008  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18009  AnsiString(VLoc) + "," + AnsiString(ELink));
18010  THVPair Route2MultiMapKeyPair;
18011 
18012  Route2MultiMapKeyPair.first = HLoc;
18013  Route2MultiMapKeyPair.second = VLoc;
18014  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18015 
18016  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18017 
18018  if(ItPair.first == ItPair.second)
18019  {
18020  RouteNumber = -1;
18021  Utilities->CallLogPop(2032);
18022  return(false);
18023  }
18024  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18025  {
18026  RouteNumber = ItPair.first->second.first;
18027  Utilities->CallLogPop(2033);
18028  return(true);
18029  }
18030  ItPair.first++;
18031 
18032  if(ItPair.first == ItPair.second)
18033  {
18034  RouteNumber = -1;
18035  Utilities->CallLogPop(2034);
18036  return(false);
18037  }
18038  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18039  {
18040  RouteNumber = ItPair.first->second.first;
18041  Utilities->CallLogPop(2035);
18042  return(true);
18043  }
18044  RouteNumber = -1;
18045  Utilities->CallLogPop(2036);
18046  return(false);
18047 }
18048 
18049 // ---------------------------------------------------------------------------
18050 
18051 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18052 /*
18053  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18054  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18055  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18056  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18057  Called by TAllRoutes::AddRouteElement.
18058 */
18059 {
18060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18061  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18062  THVPair Route2MultiMapKeyPair;
18063 
18064  Route2MultiMapKeyPair.first = HLoc;
18065  Route2MultiMapKeyPair.second = VLoc;
18066  TRoute2MultiMapEntry Route2MultiMapEntry;
18067 
18068  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18069  TRouteElementPair RouteElementPair;
18070 
18071  RouteElementPair.first = RouteNumber;
18072  RouteElementPair.second = RouteElementNumber;
18073  Route2MultiMapEntry.second = RouteElementPair;
18074 
18075  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18076  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18077  {
18078  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18079  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18080  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18081  {
18082  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18083  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18084  {
18085  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18086  }
18087  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18088  }
18089  else
18090  // same ELink so have an error
18091  {
18092  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18093  }
18094  }
18095  else
18096  {
18097  Route2MultiMap.insert(Route2MultiMapEntry);
18098  }
18099 // element at H&V not found in map so insert it
18100  Utilities->CallLogPop(399);
18101 }
18102 
18103 // ---------------------------------------------------------------------------
18104 
18106 /*
18107  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18108  and the second in the reference SecondPair. If there's only one then it's the function return
18109 */
18110 {
18111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18112  AnsiString(VLoc));
18114 
18115  TempPair.first = -1;
18116  TempPair.second = 0;
18117  SecondPair = TempPair;
18118  TRoute2MultiMapIterator Route2MultiMapIterator;
18119  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18120  THVPair Route2MultiMapKeyPair;
18121 
18122  Route2MultiMapKeyPair.first = HLoc;
18123  Route2MultiMapKeyPair.second = VLoc;
18124  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18125  {
18126  Utilities->CallLogPop(400);
18127  return(TempPair);
18128  }
18129  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18130  {
18131  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18132  Utilities->CallLogPop(401);
18133  return(Route2MultiMapIterator->second);
18134  }
18135  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18136  {
18137  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18138  TempPair = ItRange.first->second;
18139  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18140  Utilities->CallLogPop(402);
18141  return(TempPair);
18142  }
18143  Utilities->CallLogPop(403);
18144  return(TempPair);
18145 }
18146 
18147 // ---------------------------------------------------------------------------
18148 
18149 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18150 /*
18151  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18152  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18153 */
18154 {
18155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18156  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18157  {
18158  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18159  {
18160  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18161  TAllRoutes::TRouteElementPair SecondPair;
18162  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18163  if(RouteElementPair.first == -1)
18164  // failed to find element in multimap
18165  {
18166  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18167  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18168  }
18169  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18170  // neither pair has expected route number
18171  {
18172  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18173  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18174  (AnsiString)Caller);
18175  }
18176  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18177  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18178  {
18179  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18180  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18181  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18182  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18183  }
18184  }
18185  }
18186  unsigned int SizeVal = 0;
18187 
18188 // check map and sum of route sizes match
18189  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18190  {
18191  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18192  }
18193  if(SizeVal != Route2MultiMap.size())
18194  {
18195  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18196  (AnsiString)Caller);
18197  }
18198  Utilities->CallLogPop(404);
18199  return;
18200 }
18201 
18202 // ---------------------------------------------------------------------------
18203 
18204 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18205 /*
18206  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18207  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18208  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18209 */
18210 {
18211  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18212  if(!Route2MultiMap.empty())
18213  {
18214  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18215  {
18216  if(Route2MultiMapIterator->second.first > RouteNumber)
18217  {
18218  Route2MultiMapIterator->second.first--;
18219  }
18220  }
18221  }
18222  Utilities->CallLogPop(405);
18223 }
18224 
18225 // ---------------------------------------------------------------------------
18226 
18227 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18228 /*
18229  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18230  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18231  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18232 */
18233 {
18234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18235  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18236  if(!Route2MultiMap.empty())
18237  {
18238  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18239  {
18240  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18241  {
18242  Route2MultiMapIterator->second.second--;
18243  }
18244  }
18245  }
18246  Utilities->CallLogPop(406);
18247 }
18248 
18249 // ---------------------------------------------------------------------------
18250 
18251 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18252 /*
18253  Erases the route element from Route2MultiMap and from the PrefDirVector.
18254  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18255  decremented if they are greater than the element number removed, and if the entire route is removed
18256  then the route numbers are also decremented in the map for route numbers that are greater than the route
18257  number that is removed.
18258 */
18259 {
18260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18261  AnsiString(ELink));
18262  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18263  TRoute2MultiMapIterator Route2MultiMapIterator;
18264 
18265  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18266  if(RequiredRoutePair.first == -1)
18267  {
18268  throw Exception("Failed to find route element in RemoveRouteElement");
18269  }
18270  Route2MultiMap.erase(Route2MultiMapIterator);
18271  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18272 
18273 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18274  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18275 
18276  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18277  {
18278  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18279  }
18280 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18281 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18282 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18283 // to check if a route element is present, and the element has already been removed from the map - see above.
18284 
18285 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18286 /*
18287  int LockedVectorNumber = -1;
18288  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18289  {
18290  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18291  }
18292 */
18293 
18294 // erase element from route
18295  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18296  RequiredRoutePair.second)));
18297 // CheckMapAndRoutes();//test - drop - tested below
18298 
18299 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18300 // be so as continuation exit is at the end of the route, and truncation is from the end
18302  {
18304  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18305  AutoSigVectorIT--)
18306  {
18307  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18308  {
18309  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18310  }
18311  }
18312  }
18313 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18314 // and adjust all the corresponding route numbers
18315  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18316  {
18317  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18318  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18319  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18320 
18321 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18322  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18323  it is erased then - see TInterface::ApproachLocking
18324 
18325  if(LockedVectorNumber > -1)
18326  {
18327  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18328  }
18329 */
18330  // decrement route numbers in the locked route vector whether or not this route is a locked route
18331  if(!LockedRouteVector.empty())
18332  {
18333  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18334  {
18335  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18336  {
18337  LRVIT->RouteNumber--;
18338  }
18339  }
18340  }
18342  {
18344  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18345  AutoSigVectorIT--)
18346  {
18347  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18348  {
18349  AutoSigVectorIT->RouteNumber--;
18350  }
18351  }
18352  }
18353  }
18354  CheckMapAndRoutes(7); // test
18355  Utilities->CallLogPop(407);
18356 }
18357 
18358 // ---------------------------------------------------------------------------
18359 
18360 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18361 /*
18362  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18363  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18364  since that catches all route elements wherever created
18365 */
18366 {
18367  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18368  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18369  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18370  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18371  Utilities->CallLogPop(408);
18372 }
18373 
18374 // ---------------------------------------------------------------------------
18375 
18376 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18377 /*
18378  Enter with signal at TrackVectorElement already set to red by the passing train.
18379  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18380  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18381  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18382  case the function sets no further signals.
18383 */
18384 {
18385  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18386  "," + AnsiString(XLinkPos));
18387  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18388  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18389 
18390  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18391  if(RouteElementPair.first == -1)
18392  {
18393  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18394  }
18395  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18396 
18397  RequiredPair = RouteElementPair;
18398  if(RouteElement.XLinkPos != XLinkPos)
18399  {
18400  if(SecondPair.first != -1)
18401  {
18402  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18403  RequiredPair = SecondPair;
18404  if(RouteElement.XLinkPos != XLinkPos)
18405  {
18406  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18407  }
18408  }
18409  else
18410  {
18411  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18412  }
18413  }
18414 // new function
18415  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18416  Utilities->CallLogPop(409);
18417 }
18418 
18419 // ---------------------------------------------------------------------------
18420 
18421 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18422 /*
18423  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18424  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18425  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18426  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18427  to 2 for successive calls.
18428  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18429  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18430  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18431  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18432 */
18433 {
18434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18435  AnsiString(AccessNumber));
18436  TPrefDirElement RouteElement;
18437  int Attribute = AccessNumber + 1;
18438 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18439  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18440 
18441  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18442  {
18443  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18444  }
18445  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18446  {
18447  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18448  }
18449  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18450  x).XLinkPos] != End)
18451  {
18452  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18453  }
18454 // new function
18455  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18456  Utilities->CallLogPop(410);
18457 }
18458 
18459 // ---------------------------------------------------------------------------
18460 
18461 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18462 /*
18463  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18464  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18465  or (b) in a linked rear route, in which case the function sets no further signals.
18466 
18467  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18468  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18469  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18470  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18471  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18472  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18473  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18474  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18475  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18476  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18477  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18478  found behind the train.
18479 
18480  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18481  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18482  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18483  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18484  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18485  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18486  a route.
18487 
18488  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18489  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18490  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
18491  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18492  reference. If no train is found before the beginning of the route is reached the function returns true.
18493 
18494 */
18495 {
18496  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18497  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18498  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18499  int RearwardLinkedRouteNumber;
18500 
18501  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18502  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18503  // signal value in the route for use in further linked routes
18504  {
18505  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18506  {
18507  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18508  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18509  {
18510  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18511  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18512  {
18513  break;
18514  }
18515  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18516  // flash LCs on those routes
18517  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18518  }
18519  }
18520  }
18521  else
18522  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18523  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18524  {
18525  int TrainID, TrainPosition, BehindTrainPosition;
18526  bool FoundTrain = false, BehindTrain = false;
18527  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18528  {
18529  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18530  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18531  TrainID = TrackElement.TrainIDOnElement;
18532  if(TrackElement.TrackType == Bridge)
18533  {
18534  if(PrefDirElement.XLinkPos < 2)
18535  {
18536  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18537  }
18538  else
18539  {
18540  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18541  }
18542  }
18543  if(TrainID == -1)
18544  {
18545  continue;
18546  }
18547  else
18548  {
18549  FoundTrain = true;
18550  TrainPosition = x;
18551  break;
18552  }
18553  }
18554  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18555  {
18556  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18557  {
18558  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18559  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18560  // need the element behind the rearmost train.
18561  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18562  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18563  TrainID = TrackElement.TrainIDOnElement;
18564  if(TrackElement.TrackType == Bridge)
18565  {
18566  if(PrefDirElement.XLinkPos < 2)
18567  {
18568  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18569  }
18570  else
18571  {
18572  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18573  }
18574  }
18575  if(TrainID != -1)
18576  {
18577  continue; // still on train
18578  }
18579  else
18580  {
18581  BehindTrain = true;
18582  BehindTrainPosition = x;
18583  break;
18584  }
18585  }
18586  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18587  // so on for as many trains as there are on the single route
18588  {
18589  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18590  // first signal behind train to be red
18591  }
18592  }
18593  }
18594  Utilities->CallLogPop(411);
18595 }
18596 
18597 // ---------------------------------------------------------------------------
18598 
18599 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18600 {
18601 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18602  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18603  first signal is red, then OK
18604 */
18605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18606  AnsiString(RouteTruncatePosition));
18607  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18608  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18609  TPrefDirElement PrefDirElement, FirstElement;
18610  TTrackElement TrackElement;
18611  bool ExamineRoute = true;
18612 
18613  while(ExamineRoute)
18614  {
18615  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18616  {
18617  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18618  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18619  TrainID = TrackElement.TrainIDOnElement;
18620  if(TrackElement.TrackType == Bridge)
18621  {
18622  if(PrefDirElement.XLinkPos < 2)
18623  {
18624  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18625  }
18626  else
18627  {
18628  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18629  }
18630  }
18631  if(TrainID > -1)
18632  {
18633  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18634  {
18635  //any trains further back in route will be protected by the red signal behind the stopped train
18636  Utilities->CallLogPop(412);
18637  return(false);
18638  }
18639  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18640  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18641  //other way & can cancel the route
18642  {
18643  Utilities->CallLogPop(2203);
18644  return(false);
18645  }
18646  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18647  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18648  }
18649  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18650  {
18651  if(TrackElement.Attribute == 0)
18652  {
18653  Utilities->CallLogPop(413);
18654  return(false); // OK, red signal in front of a train
18655  }
18656  SignalCount++;
18657  if(SignalCount >= 3)
18658  {
18659  Utilities->CallLogPop(414);
18660  return(false);
18661  }
18662  }
18663  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18664  // ElinkPos because working back along PrefDir to beginning
18665  {
18666  Utilities->CallLogPop(415);
18667  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18668  }
18669  }
18670  //now look at linked rearwards routes
18671  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18672  StartPosition = CurrentRoute.PrefDirSize() - 1;
18673  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18674  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18675  {
18676  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18677  ExamineRoute = true;
18678  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18679  }
18680  else
18681  {
18682  // here check for a train on the element immediately before the first route element
18683  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18684  TrainID = PriorTrackElement.TrainIDOnElement;
18685  if(PriorTrackElement.TrackType == Bridge)
18686  {
18687  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18688  {
18689  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18690  }
18691  else
18692  {
18693  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18694  }
18695  }
18696  if(TrainID > -1)
18697  {
18698  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18699  {
18700  Utilities->CallLogPop(748);
18701  return(false);
18702  }
18703  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18704  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18705  //other way & can cancel the route
18706  {
18707  Utilities->CallLogPop(2204);
18708  return(false);
18709  }
18710  Utilities->CallLogPop(1962);
18711  return(true); //otherwise need to lock the route
18712  }
18713  ExamineRoute = false;
18714  }
18715  }
18716 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18717 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18718  Utilities->CallLogPop(416);
18719  return(false);
18720 }
18721 
18722 // ---------------------------------------------------------------------------
18723 
18724 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18725  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18726 {
18727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18728  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18729  TPrefDirElement InternalPrefDirElement; // blank element
18730 
18731  PrefDirElement = InternalPrefDirElement;
18732  if(LockedRouteVector.empty())
18733  {
18734  Utilities->CallLogPop(417);
18735  return(false);
18736  }
18737 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18738 // even if some elements have been removed from the front by a train
18739  bool InLockedRoute = false;
18740 
18741  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18742  {
18743  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18744  {
18745  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18746  // doesn't arise)
18747  InLockedRoute = true;
18748  break;
18749  }
18750  }
18751  if(!InLockedRoute)
18752  {
18753  Utilities->CallLogPop(418);
18754  return(false);
18755  }
18756  int RouteNumber, VectorCount = 0;
18757  TRouteType RouteType;
18758 
18759  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18760  {
18761  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18762  if(RouteType == NoRoute)
18763  {
18764  continue;
18765  }
18766  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18767  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18768  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18769  {
18770  throw Exception
18771  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18772  }
18773  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18774  {
18775  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18776  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18777  {
18778  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18779  {
18780  PrefDirElement = InternalPrefDirElement;
18781  LockedVectorNumber = VectorCount;
18782  Utilities->CallLogPop(419);
18783  return(true);
18784  }
18785  }
18786  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18787  {
18788  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18789  {
18790  PrefDirElement = InternalPrefDirElement;
18791  LockedVectorNumber = VectorCount;
18792  Utilities->CallLogPop(420);
18793  return(true);
18794  }
18795  else
18796  {
18797  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18798  }
18799  }
18800  }
18801  VectorCount++;
18802  }
18803  Utilities->CallLogPop(421);
18804  return(false);
18805 }
18806 
18807 // ---------------------------------------------------------------------------
18808 
18810 {
18811  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
18812  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18813  {
18814  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
18815  {
18816  Utilities->CallLogPop(963);
18817  return(x);
18818  }
18819  }
18820  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
18821 }
18822 
18823 // ---------------------------------------------------------------------------
18824 
18826 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
18827 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
18828 {
18829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18830  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18831  {
18832  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
18833  {
18834  Utilities->CallLogPop(2039);
18835  return(true);
18836  }
18837  }
18838  Utilities->CallLogPop(2040);
18839  return(false);
18840 }
18841 
18842 // ---------------------------------------------------------------------------
18843 
18845 {
18846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18847  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18848  {
18849  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
18850  {
18851  Utilities->CallLogPop(964);
18852  return(GetFixedRouteAt(159, x));
18853  }
18854  }
18855  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18856 }
18857 
18858 // ---------------------------------------------------------------------------
18859 
18861 {
18862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
18863  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18864  {
18865  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
18866  {
18867  Utilities->CallLogPop(965);
18868  return(GetModifiableRouteAt(15, x));
18869  }
18870  }
18871  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18872 }
18873 
18874 // ---------------------------------------------------------------------------
18875 
18876 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
18877 {
18878  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
18879  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
18880  Utilities->SaveFileInt(OutFile, NextRouteID);
18881  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18882  {
18883  TOneRoute OneRoute = GetFixedRouteAt(165, x);
18884  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
18885  OneRoute.SavePrefDirVector(6, OutFile);
18886  }
18887  Utilities->CallLogPop(1442);
18888 }
18889 
18890 // ---------------------------------------------------------------------------
18891 
18892 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
18893 {
18894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
18895  int NumberOfRoutes;
18896 
18897  NumberOfRoutes = Utilities->LoadFileInt(InFile);
18898  NextRouteID = Utilities->LoadFileInt(InFile);
18899  for(int x = 0; x < NumberOfRoutes; x++)
18900  {
18901  TOneRoute OneRoute; // empty route
18902  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
18903  OneRoute.LoadPrefDir(2, InFile);
18905  {
18906  StoreOneRouteAfterSessionLoad(0, &OneRoute);
18907  }
18908  else
18909  {
18910  Utilities->CallLogPop(1443);
18911  return(false);
18912  }
18913  }
18914  Utilities->CallLogPop(1444);
18915  return(true);
18916 }
18917 
18918 // ---------------------------------------------------------------------------
18919 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
18920 {
18921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
18922  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
18923 
18924  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
18925  {
18926  Utilities->CallLogPop(1445);
18927  return(false);
18928  }
18929  int NextID = Utilities->LoadFileInt(InFile);
18930 
18931  if((NextID < 0) || (NextID > 1000000))
18932  {
18933  Utilities->CallLogPop(1446);
18934  return(false);
18935  }
18936  for(int x = 0; x < NumberOfRoutes; x++)
18937  {
18938  int RouteID = Utilities->LoadFileInt(InFile);
18939  if((RouteID < 0) || (RouteID > 20000))
18940  {
18941  Utilities->CallLogPop(1447);
18942  return(false);
18943  }
18944  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
18945  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
18946  {
18947  Utilities->CallLogPop(1448);
18948  return(false);
18949  }
18950  }
18951  Utilities->CallLogPop(1449);
18952  return(true);
18953 }
18954 
18955 // ---------------------------------------------------------------------------
18956 
18957 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
18958 {
18959  // return true for a loop
18960  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
18961  AnsiString(StartPosition));
18962  if(EndPosition == StartPosition)
18963  {
18964  Utilities->CallLogPop(1839);
18965  return(true); // shouldn't happen but treat as a loop if does
18966  }
18967 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
18968  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
18969  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
18970 
18971  while(TrackIsInARoute(15, TVPos, LkPos))
18972  {
18973  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
18974  int NewLkPos = -1;
18975  if(NewTVPos > -1)
18976  {
18977  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
18978  if(NewLkPos == -1)
18979  {
18980  Utilities->CallLogPop(1840);
18981  return(true); // shouldn't arise but treat as loop if does
18982  }
18983  }
18984  else // reached a buffer or continuation
18985  {
18986  Utilities->CallLogPop(1841);
18987  return(false);
18988  }
18989 //Error found by Xeon notified by email 13/10/20.
18990 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
18991 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
18992 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
18993 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
18994 //New check added for v2.6.0
18995 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
18996 //as possible in case there are other unforeseen effects.
18997  int RouteNumber; //dummy, not used
18998  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
18999  {
19000  Utilities->CallLogPop(2241);
19001  return(false);
19002  }
19003  //now make the connected element the current element, read across the TV number and determine the exit link
19004  TVPos = NewTVPos;
19005  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19006  {
19007  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19008  {
19009  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19010  {
19011  LkPos = 1;
19012  }
19013  else
19014  {
19015  LkPos = 3;
19016  }
19017  }
19018  else
19019  {
19020  LkPos = 0;
19021  }
19022  }
19023  else
19024  {
19025  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19026  }
19027  if(TVPos == StartPosition)
19028  {
19029  Utilities->CallLogPop(1842);
19030  return(true); // it is a loop
19031  }
19032  }
19033  Utilities->CallLogPop(1843);
19034  return(false); // reached end of route so not a loop
19035 }
19036 
19037 // ---------------------------------------------------------------------------
19038 
19039 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19040 /*
19041  Track geometry allows diagonals to cross without occupying the same track element, so when
19042  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19043  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19044  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19045  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19046  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19047  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19048  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19049  Each of these is examined in turn for each route element in the relevant position.
19050 
19051  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19052  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19053  that returns false in all cases (including elements & links not present) except train present.
19054 */
19055 {
19056  int TrainID; // not used in this function
19057 
19058  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19059  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19060  TPrefDirElement TempPrefDirElement;
19061  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19062 
19063  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19064  if(FirstPair.first > -1)
19065  {
19066  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19067  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19068  {
19069  Utilities->CallLogPop(310);
19070  return(true);
19071  }
19072  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19073  {
19074  Utilities->CallLogPop(311);
19075  return(true);
19076  }
19077  }
19078  if(SecondPair.first > -1)
19079  {
19080  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19081  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19082  {
19083  Utilities->CallLogPop(312);
19084  return(true);
19085  }
19086  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19087  {
19088  Utilities->CallLogPop(313);
19089  return(true);
19090  }
19091  }
19092  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19093  9, TrainID)))
19094  {
19095  Utilities->CallLogPop(1997);
19096  return(true);
19097  }
19098  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19099  if(FirstPair.first > -1)
19100  {
19101  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19102  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19103  {
19104  Utilities->CallLogPop(314);
19105  return(true);
19106  }
19107  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19108  {
19109  Utilities->CallLogPop(315);
19110  return(true);
19111  }
19112  }
19113  if(SecondPair.first > -1)
19114  {
19115  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19116  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19117  {
19118  Utilities->CallLogPop(316);
19119  return(true);
19120  }
19121  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19122  {
19123  Utilities->CallLogPop(317);
19124  return(true);
19125  }
19126  }
19127  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19128  9, TrainID)))
19129  {
19130  Utilities->CallLogPop(1998);
19131  return(true);
19132  }
19133  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19134  if(FirstPair.first > -1)
19135  {
19136  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19137  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19138  {
19139  Utilities->CallLogPop(318);
19140  return(true);
19141  }
19142  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19143  {
19144  Utilities->CallLogPop(319);
19145  return(true);
19146  }
19147  }
19148  if(SecondPair.first > -1)
19149  {
19150  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19151  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19152  {
19153  Utilities->CallLogPop(320);
19154  return(true);
19155  }
19156  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19157  {
19158  Utilities->CallLogPop(321);
19159  return(true);
19160  }
19161  }
19162  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19163  7, TrainID)))
19164  {
19165  Utilities->CallLogPop(1999);
19166  return(true);
19167  }
19168  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19169  if(FirstPair.first > -1)
19170  {
19171  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19172  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19173  {
19174  Utilities->CallLogPop(322);
19175  return(true);
19176  }
19177  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19178  {
19179  Utilities->CallLogPop(323);
19180  return(true);
19181  }
19182  }
19183  if(SecondPair.first > -1)
19184  {
19185  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19186  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19187  {
19188  Utilities->CallLogPop(324);
19189  return(true);
19190  }
19191  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19192  {
19193  Utilities->CallLogPop(325);
19194  return(true);
19195  }
19196  }
19197  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19198  3, TrainID)))
19199  {
19200  Utilities->CallLogPop(2000);
19201  return(true);
19202  }
19203  Utilities->CallLogPop(326);
19204  return(false);
19205 }
19206 
19207 // ---------------------------------------------------------------------------
19208 
19209 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19210 /*
19211  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19212  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19213  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19214  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19215  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19216  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19217  Each of these is examined in turn for each route element in the relevant position.
19218 */
19219 {
19220  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19221  "," + AnsiString(DiagonalLinkNumber));
19222  TPrefDirElement TempPrefDirElement;
19223  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19224 
19225  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19226  if(FirstPair.first > -1)
19227  {
19228  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19229  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19230  {
19231  Utilities->CallLogPop(2010);
19232  return(true);
19233  }
19234  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19235  {
19236  Utilities->CallLogPop(2011);
19237  return(true);
19238  }
19239  }
19240  if(SecondPair.first > -1)
19241  {
19242  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19243  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19244  {
19245  Utilities->CallLogPop(2012);
19246  return(true);
19247  }
19248  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19249  {
19250  Utilities->CallLogPop(2013);
19251  return(true);
19252  }
19253  }
19254  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19255  if(FirstPair.first > -1)
19256  {
19257  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19258  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19259  {
19260  Utilities->CallLogPop(2014);
19261  return(true);
19262  }
19263  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19264  {
19265  Utilities->CallLogPop(2015);
19266  return(true);
19267  }
19268  }
19269  if(SecondPair.first > -1)
19270  {
19271  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19272  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19273  {
19274  Utilities->CallLogPop(2016);
19275  return(true);
19276  }
19277  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19278  {
19279  Utilities->CallLogPop(2017);
19280  return(true);
19281  }
19282  }
19283  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19284  if(FirstPair.first > -1)
19285  {
19286  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19287  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19288  {
19289  Utilities->CallLogPop(2018);
19290  return(true);
19291  }
19292  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19293  {
19294  Utilities->CallLogPop(2019);
19295  return(true);
19296  }
19297  }
19298  if(SecondPair.first > -1)
19299  {
19300  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19301  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19302  {
19303  Utilities->CallLogPop(2020);
19304  return(true);
19305  }
19306  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19307  {
19308  Utilities->CallLogPop(2021);
19309  return(true);
19310  }
19311  }
19312  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19313  if(FirstPair.first > -1)
19314  {
19315  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19316  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19317  {
19318  Utilities->CallLogPop(2022);
19319  return(true);
19320  }
19321  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19322  {
19323  Utilities->CallLogPop(2023);
19324  return(true);
19325  }
19326  }
19327  if(SecondPair.first > -1)
19328  {
19329  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19330  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19331  {
19332  Utilities->CallLogPop(2024);
19333  return(true);
19334  }
19335  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19336  {
19337  Utilities->CallLogPop(2025);
19338  return(true);
19339  }
19340  }
19341  Utilities->CallLogPop(2026);
19342  return(false);
19343 }
19344 
19345 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8320
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:677
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17455
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1259
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:917
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11241
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:663
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:730
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:613
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:565
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11214
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:415
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:549
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:875
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5381
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12760
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:772
TFixedTrackPiece
Definition: TrackUnit.h:84
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1665
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:767
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:908
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18051
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:94
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:791
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:909
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9806
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:793
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18461
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:920
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1313
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:759
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:581
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:702
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13180
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:759
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:620
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:774
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:413
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12800
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:679
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3625
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:700
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:881
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:757
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:307
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7061
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1582
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:16967
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:684
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1645
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:693
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5533
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6962
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5560
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1467
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:569
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1606
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:826
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:847
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1909
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:914
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10140
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:599
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16731
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:612
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:906
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19209
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:415
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1636
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:590
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2733
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:534
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5713
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:728
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:672
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7980
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1477
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:628
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:17889
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:763
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:561
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:666
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12539
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7447
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9381
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9184
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13828
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14841
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:566
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17415
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18251
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:857
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:855
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1586
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:873
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12343
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:160
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4355
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3571
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:673
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:831
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1489
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:582
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:760
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:796
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7795
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:421
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:662
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:585
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1026
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4515
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1273
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6245
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10625
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:654
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:868
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3447
Unused
@ Unused
Definition: TrackUnit.h:67
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:587
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:617
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1272
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:705
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18724
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2766
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:770
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:254
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:18919
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:557
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9351
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1644
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1487
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1573
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:223
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:918
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:676
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:419
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3171
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15414
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:777
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:669
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8247
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12605
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:761
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:794
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2782
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:695
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1006
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:17999
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:775
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:819
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1340
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:706
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12856
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1715
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:595
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5673
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:670
TTrain
Definition: TrainUnit.h:279
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:373
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13699
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11255
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:561
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:553
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:609
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7462
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:67
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:790
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18360
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:856
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7208
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:921
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:590
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:628
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:551
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10245
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:584
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1491
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1455
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:698
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:649
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:563
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:763
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:761
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:715
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1349
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5905
End
@ End
Definition: TrackUnit.h:77
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1493
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:668
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:843
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:601
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8601
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:864
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:904
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:546
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:10354
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1019
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:319
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:800
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:708
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:769
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:578
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:914
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:127
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:723
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:758
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3738
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:990
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:825
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:991
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:258
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:701
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9316
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1000
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17403
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:485
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:778
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1071
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1610
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:792
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:827
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7476
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:650
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6654
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:626
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:256
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:685
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8640
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:907
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:817
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17388
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:756
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:569
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:657
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:778
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:801
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:76
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13469
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13206
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:714
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:878
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:66
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4440
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1859
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:814
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:829
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:594
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:804
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:413
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:743
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:96
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:816
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:575
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:10828
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18204
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4674
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:160
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1878
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:674
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:789
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:925
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:722
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:541
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:586
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:720
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:835
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:444
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:635
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11073
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:18825
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:569
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1017
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:611
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2750
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:710
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1499
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7433
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14645
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7089
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8437
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7168
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:667
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:721
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:672
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:292
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:663
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1275
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:825
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:803
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:802
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12944
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:766
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:867
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12079
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1611
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1663
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:47
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:905
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:588
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12572
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:652
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17175
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3548
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13159
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11116
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10491
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1761
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:764
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:890
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:560
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5767
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12392
Under
@ Under
Definition: TrackUnit.h:77
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16699
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:778
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:696
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:605
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2805
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11267
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11587
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:871
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:410
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:137
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10389
Lead
@ Lead
Definition: TrackUnit.h:77
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5632
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1795
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13407
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:844
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:554
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3764
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5424
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6226
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:87
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1304
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9112
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:579
TTrack::Up
@ Up
Definition: TrackUnit.h:590
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:863
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:780
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:564
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10368
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:924
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1449
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8404
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1604
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:720
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:219
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17242
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1593
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:781
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6112
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:782
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:623
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8350
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:783
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7117
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9779
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:77
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:551
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:569
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:750
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17692
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:155
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1529
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12442
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11012
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4524
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:549
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:10340
TGraphicElement::Width
int Width
Definition: TrackUnit.h:417
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18599
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:18809
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17518
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:755
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:742
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:570
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:636
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:4065
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:771
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14237
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:637
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4043
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2340
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:670
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9252
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12210
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:589
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:862
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:917
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5608
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18892
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:568
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1491
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:911
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:769
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1480
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:828
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6815
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:724
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap Map, TTrackVector Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5584
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1030
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1032
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7648
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17334
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:638
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7190
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:785
Erase
@ Erase
Definition: TrackUnit.h:68
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:832
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5229
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:778
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1643
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:812
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:859
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:576
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13229
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:597
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:10924
Parapet
@ Parapet
Definition: TrackUnit.h:68
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17361
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:786
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:994
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:295
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8921
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17307
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:852
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:778
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18227
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:591
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:916
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:753
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:784
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:807
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1035
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:703
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:799
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14450
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:824
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:139
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:221
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11144
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12137
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1253
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17270
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:597
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:732
TTrack
Definition: TrackUnit.h:527
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1312
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:825
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1343
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18376
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1580
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7949
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:621
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:567
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:841
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:651
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:727
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:850
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:130
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:806
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:686
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:219
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:17867
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:227
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8691
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:910
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6006
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2092
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:566
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:725
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:160
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:845
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:761
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2558
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:217
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1578
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7612
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11925
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12703
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:565
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1455
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10277
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8313
IDInt
Definition: TrackUnit.h:476
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2321
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:574
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:18860
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:598
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:779
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4328
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10027
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4974
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:808
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:773
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:822
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:419
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:18957
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1106
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9035
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:549
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:99
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7559
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1254
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:887
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13013
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:739
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:731
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:632
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:225
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:848
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14033
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1648
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:132
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:768
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7527
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:611
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:809
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:782
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:716
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:860
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:755
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1466
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:839
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1584
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:836
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1594
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4596
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:571
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:8861
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:655
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15220
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1282
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:717
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:413
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13335
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:813
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1260
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13110
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
Points
@ Points
Definition: TrackUnit.h:67
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:703
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:724
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:17940
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:854
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9710
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:10995
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:583
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:821
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
Trail
@ Trail
Definition: TrackUnit.h:77
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17219
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9094
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16818
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:762
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1831
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:805
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16636
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:818
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:648
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:726
Continuation
@ Continuation
Definition: TrackUnit.h:67
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1026
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7406
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3648
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5844
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:569
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9141
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:853
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:861
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:869
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11968
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:555
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:823
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:753
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:858
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:413
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14681
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:569
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1015
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3265
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:417
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:874
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1483
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:689
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:622
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:705
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1642
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:912
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:289
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:729
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:837
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19039
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:12908
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1004
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:767
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1457
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1008
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:745
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:616
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:854
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4581
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:872
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:17838
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1675
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8451
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:699
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:674
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:577
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:765
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:653
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10782
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:811
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:685
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1314
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18876
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:559
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1841
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4566
Connection
@ Connection
Definition: TrackUnit.h:77
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3625
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1650
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9373
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:995
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:733
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16449
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11786
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:707
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:810
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8377
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:860
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1013
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18149
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18105
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6888
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10653
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:692
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:851
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:699
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1341
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:884
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5652
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:844
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:708
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:413
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:732
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9833
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:551
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:701
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:712
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17375
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4706
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:788
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2661
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:675
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7487
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3027
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:840
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:134
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:865
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16607
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:607
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13599
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:730
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:590
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:671
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:614
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1254
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:632
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:642
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:900
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:625
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11346
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:413
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:919
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:102
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1453
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:214
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8500
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:798
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1739
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8682
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:626
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:572
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:689
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13306
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:18844
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:589
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1311
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4188
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:771
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4457
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7350
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1936
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1021
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6152
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:992
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:695
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:825
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:627
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7145
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1343
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:227
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:644
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:870
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:736
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:651
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4482
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:747
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1588
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1028
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:765
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:922
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7900
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:665
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1267
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:795
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:830
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9290
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1002
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:754
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10889
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1746
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:815
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:624
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1455
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15641
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7333
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:773
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:780
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:678
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1457
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:594
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6169
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:709
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3525
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:757
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:643
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:562
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:787
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:718
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10815
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:774
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:866
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:834
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:658
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:913
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:279
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:694
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:603
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:713
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1054
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:567
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16015
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:665
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:776
RouteCall
@ RouteCall
Definition: TrackUnit.h:1260
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11280
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:846
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:592
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:77
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:648
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18421
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:241
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:593
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:580
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10844
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10109
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:653
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:532
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:217
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:776
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:915
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6070
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:160
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:923
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:710
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11292
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1316
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1511
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:838
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:722
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:808
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:693
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:551
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:615
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10100
Bridge
@ Bridge
Definition: TrackUnit.h:67
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:849
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1254
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:797
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:77
Buffers
@ Buffers
Definition: TrackUnit.h:67
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16365
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:690
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:77
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11304
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4394
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11227
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:833